doc: updated italian translations
[adg.git] / src / adg / adg-text.c
blobb4604f9041a1a76068c0ba636ea7a68aa703b4d6
1 /* ADG - Automatic Drawing Generation
2 * Copyright (C) 2007,2008,2009,2010,2011,2012 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.
21 /**
22 * SECTION:adg-text
23 * @short_description: A pango based text entity
25 * The #AdgText class is the main class for showing text. It works
26 * the same way as #AdgToyText but uses pango instead of the so
27 * called cairo "toy" API.
29 * The text entity is not subject to the local matrix, only its origin is.
31 * Since: 1.0
32 **/
34 /**
35 * AdgText:
37 * All fields are privates and should not be used directly.
38 * Use its public methods instead.
40 * Since: 1.0
41 **/
44 #include "adg-internal.h"
45 #include <pango/pangocairo.h>
47 #include "adg-dress.h"
48 #include "adg-dress-builtins.h"
49 #include "adg-style.h"
50 #include "adg-font-style.h"
51 #include "adg-pango-style.h"
52 #include "adg-textual.h"
54 #include "adg-text.h"
55 #include "adg-text-private.h"
58 #define _ADG_OLD_OBJECT_CLASS ((GObjectClass *) adg_text_parent_class)
59 #define _ADG_OLD_ENTITY_CLASS ((AdgEntityClass *) adg_text_parent_class)
62 static void _adg_iface_init (AdgTextualIface *iface);
65 G_DEFINE_TYPE_WITH_CODE(AdgText, adg_text, ADG_TYPE_ENTITY,
66 G_IMPLEMENT_INTERFACE(ADG_TYPE_TEXTUAL, _adg_iface_init))
68 enum {
69 PROP_0,
70 PROP_FONT_DRESS,
71 PROP_TEXT
75 static void _adg_dispose (GObject *object);
76 static void _adg_finalize (GObject *object);
77 static void _adg_get_property (GObject *object,
78 guint param_id,
79 GValue *value,
80 GParamSpec *pspec);
81 static void _adg_set_property (GObject *object,
82 guint param_id,
83 const GValue *value,
84 GParamSpec *pspec);
85 static void _adg_global_changed (AdgEntity *entity);
86 static void _adg_local_changed (AdgEntity *entity);
87 static void _adg_invalidate (AdgEntity *entity);
88 static void _adg_arrange (AdgEntity *entity);
89 static void _adg_render (AdgEntity *entity,
90 cairo_t *cr);
91 static void _adg_set_font_dress (AdgTextual *textual,
92 AdgDress dress);
93 static AdgDress _adg_get_font_dress (AdgTextual *textual);
94 static void _adg_set_text (AdgTextual *textual,
95 const gchar *text);
96 static gchar * _adg_dup_text (AdgTextual *textual);
97 static void _adg_refresh_extents (AdgText *text);
98 static void _adg_clear_layout (AdgText *text);
101 static void
102 adg_text_class_init(AdgTextClass *klass)
104 GObjectClass *gobject_class;
105 AdgEntityClass *entity_class;
107 gobject_class = (GObjectClass *) klass;
108 entity_class = (AdgEntityClass *) klass;
110 g_type_class_add_private(klass, sizeof(AdgTextPrivate));
112 gobject_class->dispose = _adg_dispose;
113 gobject_class->finalize = _adg_finalize;
114 gobject_class->get_property = _adg_get_property;
115 gobject_class->set_property = _adg_set_property;
117 entity_class->global_changed = _adg_global_changed;
118 entity_class->local_changed = _adg_local_changed;
119 entity_class->invalidate = _adg_invalidate;
120 entity_class->arrange = _adg_arrange;
121 entity_class->render = _adg_render;
123 g_object_class_override_property(gobject_class, PROP_FONT_DRESS, "font-dress");
124 g_object_class_override_property(gobject_class, PROP_TEXT, "text");
127 static void
128 _adg_iface_init(AdgTextualIface *iface)
130 iface->set_font_dress = _adg_set_font_dress;
131 iface->get_font_dress = _adg_get_font_dress;
132 iface->set_text = _adg_set_text;
133 iface->dup_text = _adg_dup_text;
134 iface->text_changed = NULL;
137 static void
138 adg_text_init(AdgText *text)
140 AdgTextPrivate *data = G_TYPE_INSTANCE_GET_PRIVATE(text, ADG_TYPE_TEXT,
141 AdgTextPrivate);
143 data->font_dress = ADG_DRESS_FONT_TEXT;
144 data->text = NULL;
145 data->layout = NULL;
147 text->data = data;
150 static void
151 _adg_dispose(GObject *object)
153 AdgText *text = (AdgText *) object;
155 _adg_clear_layout(text);
157 if (_ADG_OLD_OBJECT_CLASS->dispose)
158 _ADG_OLD_OBJECT_CLASS->dispose(object);
161 static void
162 _adg_finalize(GObject *object)
164 AdgText *text;
165 AdgTextPrivate *data;
167 text = (AdgText *) object;
168 data = text->data;
170 g_free(data->text);
172 if (_ADG_OLD_OBJECT_CLASS->finalize)
173 _ADG_OLD_OBJECT_CLASS->finalize(object);
176 static void
177 _adg_get_property(GObject *object, guint prop_id,
178 GValue *value, GParamSpec *pspec)
180 AdgTextPrivate *data = ((AdgText *) object)->data;
182 switch (prop_id) {
183 case PROP_FONT_DRESS:
184 g_value_set_int(value, data->font_dress);
185 break;
186 case PROP_TEXT:
187 g_value_set_string(value, data->text);
188 break;
189 default:
190 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
191 break;
195 static void
196 _adg_set_property(GObject *object, guint prop_id,
197 const GValue *value, GParamSpec *pspec)
199 AdgText *text;
200 AdgTextPrivate *data;
202 text = (AdgText *) object;
203 data = text->data;
205 switch (prop_id) {
206 case PROP_FONT_DRESS:
207 data->font_dress = g_value_get_int(value);
208 _adg_clear_layout(text);
209 break;
210 case PROP_TEXT:
211 g_free(data->text);
212 data->text = g_value_dup_string(value);
213 _adg_clear_layout(text);
214 break;
215 default:
216 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
217 break;
223 * adg_text_new:
224 * @text: the text
226 * Creates a new text entity using @text as its content.
227 * The #AdgEntity:local-method property is set by default to
228 * #ADG_LOCAL_NORMALIZED.
230 * Returns: the newly created text entity
232 * Since: 1.0
234 AdgText *
235 adg_text_new(const gchar *text)
237 return g_object_new(ADG_TYPE_TEXT,
238 "local-method", ADG_MIX_ANCESTORS_NORMALIZED,
239 "text", text, NULL);
243 static void
244 _adg_global_changed(AdgEntity *entity)
246 if (_ADG_OLD_ENTITY_CLASS->global_changed != NULL)
247 _ADG_OLD_ENTITY_CLASS->global_changed(entity);
249 _adg_refresh_extents((AdgText *) entity);
252 static void
253 _adg_local_changed(AdgEntity *entity)
255 if (_ADG_OLD_ENTITY_CLASS->local_changed != NULL)
256 _ADG_OLD_ENTITY_CLASS->local_changed(entity);
258 _adg_refresh_extents((AdgText *) entity);
261 static void
262 _adg_invalidate(AdgEntity *entity)
264 _adg_clear_layout((AdgText *) entity);
266 if (_ADG_OLD_ENTITY_CLASS->invalidate)
267 _ADG_OLD_ENTITY_CLASS->invalidate(entity);
270 static void
271 _adg_arrange(AdgEntity *entity)
273 AdgText *text;
274 AdgTextPrivate *data;
275 PangoRectangle size;
277 text = (AdgText *) entity;
278 data = text->data;
280 if (adg_is_string_empty(data->text)) {
281 /* Undefined text */
282 CpmlExtents new_extents;
283 new_extents.is_defined = FALSE;
284 adg_entity_set_extents(entity, &new_extents);
285 _adg_clear_layout(text);
286 return;
287 } else if (data->layout != NULL) {
288 /* Cached result */
289 return;
292 if (data->layout == NULL) {
293 static PangoFontMap *font_map = NULL;
294 AdgDress dress;
295 AdgPangoStyle *pango_style;
296 PangoFontDescription *font_description;
297 cairo_font_options_t *options;
298 PangoContext *context;
300 /* Keep around a font_map object. The rationale is here:
301 * https://bugzilla.gnome.org/show_bug.cgi?id=143542
303 * Basically, PangoFontMap is an heavy object and
304 * creating/destroying it is not the right way.
306 * In reality, the blocking issue for me was the following
307 * line make the adg-demo program crash on MinGW32:
308 * g_object_unref(font_map);
310 if (font_map == NULL)
311 font_map = pango_cairo_font_map_new();
313 dress = data->font_dress;
314 pango_style = (AdgPangoStyle *) adg_entity_style(entity, dress);
315 font_description = adg_pango_style_get_description(pango_style);
317 context = pango_context_new();
318 pango_context_set_font_map(context, font_map);
319 pango_cairo_context_set_resolution(context, 72);
321 options = adg_font_style_new_options((AdgFontStyle *) pango_style);
322 pango_cairo_context_set_font_options(context, options);
323 cairo_font_options_destroy(options);
325 data->layout = pango_layout_new(context);
326 g_object_unref(context);
328 pango_layout_set_text(data->layout, data->text, -1);
329 pango_layout_set_font_description(data->layout, font_description);
332 pango_layout_get_extents(data->layout, NULL, &size);
334 data->raw_extents.org.x = pango_units_to_double(size.x);
335 data->raw_extents.org.y = pango_units_to_double(size.y);
336 data->raw_extents.size.x = pango_units_to_double(size.width);
337 data->raw_extents.size.y = pango_units_to_double(size.height);
338 data->raw_extents.is_defined = TRUE;
340 _adg_refresh_extents((AdgText *) entity);
343 static void
344 _adg_render(AdgEntity *entity, cairo_t *cr)
346 AdgText *text;
347 AdgTextPrivate *data;
349 text = (AdgText *) entity;
350 data = text->data;
352 if (data->layout != NULL) {
353 adg_entity_apply_dress(entity, data->font_dress, cr);
354 cairo_transform(cr, adg_entity_get_global_matrix(entity));
355 cairo_transform(cr, adg_entity_get_local_matrix(entity));
357 /* Realign the text to follow the cairo toy text convention:
358 * use bottom/left corner as reference (pango uses top/left). */
359 cairo_translate(cr, 0, -data->raw_extents.size.y);
361 pango_cairo_update_layout(cr, data->layout);
362 pango_cairo_show_layout(cr, data->layout);
366 static void
367 _adg_set_font_dress(AdgTextual *textual, AdgDress dress)
369 g_object_set(textual, "font-dress", dress, NULL);
372 static AdgDress
373 _adg_get_font_dress(AdgTextual *textual)
375 AdgTextPrivate *data = ((AdgText *) textual)->data;
376 return data->font_dress;
379 static void
380 _adg_set_text(AdgTextual *textual, const gchar *text)
382 g_object_set(textual, "text", text, NULL);
385 static gchar *
386 _adg_dup_text(AdgTextual *textual)
388 AdgTextPrivate *data = ((AdgText *) textual)->data;
389 return g_strdup(data->text);
392 static void
393 _adg_refresh_extents(AdgText *text)
395 AdgTextPrivate *data;
396 AdgEntity *entity;
397 AdgMatrix ctm;
398 CpmlExtents new_extents;
400 data = text->data;
402 if (! data->raw_extents.is_defined)
403 return;
405 entity = (AdgEntity *) text;
407 adg_matrix_copy(&ctm, adg_entity_get_global_matrix(entity));
408 adg_matrix_transform(&ctm, adg_entity_get_local_matrix(entity),
409 ADG_TRANSFORM_AFTER);
410 cpml_extents_copy(&new_extents, &data->raw_extents);
412 /* Realign the text to follow the cairo toy text convention:
413 * use bottom/left corner as reference (pango uses top/left). */
414 new_extents.org.y -= new_extents.size.y;
416 cpml_extents_transform(&new_extents, &ctm);
417 adg_entity_set_extents(entity, &new_extents);
420 static void
421 _adg_clear_layout(AdgText *text)
423 AdgTextPrivate *data = text->data;
425 if (data->layout != NULL) {
426 g_object_unref(data->layout);
427 data->layout = NULL;