Tested build process under ss-dev of OpenIndiana
[adg.git] / src / adg / adg-text.c
blobdcaccc531455b4544515e449debe261ae40ef729
1 /* ADG - Automatic Drawing Generation
2 * Copyright (C) 2007,2008,2009,2010,2011 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.
30 **/
32 /**
33 * AdgText:
35 * All fields are privates and should not be used directly.
36 * Use its public methods instead.
37 **/
40 #include "adg-internal.h"
41 #include <pango/pangocairo.h>
43 #include "adg-dress.h"
44 #include "adg-dress-builtins.h"
45 #include "adg-style.h"
46 #include "adg-font-style.h"
47 #include "adg-pango-style.h"
48 #include "adg-textual.h"
50 #include "adg-text.h"
51 #include "adg-text-private.h"
54 #define _ADG_OLD_OBJECT_CLASS ((GObjectClass *) adg_text_parent_class)
55 #define _ADG_OLD_ENTITY_CLASS ((AdgEntityClass *) adg_text_parent_class)
58 static void _adg_iface_init (AdgTextualIface *iface);
61 G_DEFINE_TYPE_WITH_CODE(AdgText, adg_text, ADG_TYPE_ENTITY,
62 G_IMPLEMENT_INTERFACE(ADG_TYPE_TEXTUAL, _adg_iface_init))
64 enum {
65 PROP_0,
66 PROP_FONT_DRESS,
67 PROP_TEXT
71 static void _adg_dispose (GObject *object);
72 static void _adg_finalize (GObject *object);
73 static void _adg_get_property (GObject *object,
74 guint param_id,
75 GValue *value,
76 GParamSpec *pspec);
77 static void _adg_set_property (GObject *object,
78 guint param_id,
79 const GValue *value,
80 GParamSpec *pspec);
81 static void _adg_global_changed (AdgEntity *entity);
82 static void _adg_local_changed (AdgEntity *entity);
83 static void _adg_invalidate (AdgEntity *entity);
84 static void _adg_arrange (AdgEntity *entity);
85 static void _adg_render (AdgEntity *entity,
86 cairo_t *cr);
87 static void _adg_set_font_dress (AdgTextual *textual,
88 AdgDress dress);
89 static AdgDress _adg_get_font_dress (AdgTextual *textual);
90 static void _adg_set_text (AdgTextual *textual,
91 const gchar *text);
92 static gchar * _adg_dup_text (AdgTextual *textual);
93 static void _adg_refresh_extents (AdgText *text);
94 static void _adg_clear_layout (AdgText *text);
97 static void
98 adg_text_class_init(AdgTextClass *klass)
100 GObjectClass *gobject_class;
101 AdgEntityClass *entity_class;
103 gobject_class = (GObjectClass *) klass;
104 entity_class = (AdgEntityClass *) klass;
106 g_type_class_add_private(klass, sizeof(AdgTextPrivate));
108 gobject_class->dispose = _adg_dispose;
109 gobject_class->finalize = _adg_finalize;
110 gobject_class->get_property = _adg_get_property;
111 gobject_class->set_property = _adg_set_property;
113 entity_class->global_changed = _adg_global_changed;
114 entity_class->local_changed = _adg_local_changed;
115 entity_class->invalidate = _adg_invalidate;
116 entity_class->arrange = _adg_arrange;
117 entity_class->render = _adg_render;
119 g_object_class_override_property(gobject_class, PROP_FONT_DRESS, "font-dress");
120 g_object_class_override_property(gobject_class, PROP_TEXT, "text");
123 static void
124 _adg_iface_init(AdgTextualIface *iface)
126 iface->set_font_dress = _adg_set_font_dress;
127 iface->get_font_dress = _adg_get_font_dress;
128 iface->set_text = _adg_set_text;
129 iface->dup_text = _adg_dup_text;
130 iface->text_changed = NULL;
133 static void
134 adg_text_init(AdgText *text)
136 AdgTextPrivate *data = G_TYPE_INSTANCE_GET_PRIVATE(text, ADG_TYPE_TEXT,
137 AdgTextPrivate);
139 data->font_dress = ADG_DRESS_FONT_TEXT;
140 data->text = NULL;
141 data->layout = NULL;
143 text->data = data;
146 static void
147 _adg_dispose(GObject *object)
149 AdgText *text = (AdgText *) object;
151 _adg_clear_layout(text);
153 if (_ADG_OLD_OBJECT_CLASS->dispose)
154 _ADG_OLD_OBJECT_CLASS->dispose(object);
157 static void
158 _adg_finalize(GObject *object)
160 AdgText *text;
161 AdgTextPrivate *data;
163 text = (AdgText *) object;
164 data = text->data;
166 g_free(data->text);
168 if (_ADG_OLD_OBJECT_CLASS->finalize)
169 _ADG_OLD_OBJECT_CLASS->finalize(object);
172 static void
173 _adg_get_property(GObject *object, guint prop_id,
174 GValue *value, GParamSpec *pspec)
176 AdgTextPrivate *data = ((AdgText *) object)->data;
178 switch (prop_id) {
179 case PROP_FONT_DRESS:
180 g_value_set_int(value, data->font_dress);
181 break;
182 case PROP_TEXT:
183 g_value_set_string(value, data->text);
184 break;
185 default:
186 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
187 break;
191 static void
192 _adg_set_property(GObject *object, guint prop_id,
193 const GValue *value, GParamSpec *pspec)
195 AdgText *text;
196 AdgTextPrivate *data;
198 text = (AdgText *) object;
199 data = text->data;
201 switch (prop_id) {
202 case PROP_FONT_DRESS:
203 data->font_dress = g_value_get_int(value);
204 _adg_clear_layout(text);
205 break;
206 case PROP_TEXT:
207 g_free(data->text);
208 data->text = g_value_dup_string(value);
209 _adg_clear_layout(text);
210 break;
211 default:
212 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
213 break;
219 * adg_text_new:
220 * @text: the text
222 * Creates a new text entity using @text as its content.
223 * The #AdgEntity:local-method property is set by default to
224 * #ADG_LOCAL_NORMALIZED.
226 * Returns: the newly created text entity
228 AdgText *
229 adg_text_new(const gchar *text)
231 return g_object_new(ADG_TYPE_TEXT,
232 "local-method", ADG_MIX_ANCESTORS_NORMALIZED,
233 "text", text, NULL);
237 static void
238 _adg_global_changed(AdgEntity *entity)
240 if (_ADG_OLD_ENTITY_CLASS->global_changed != NULL)
241 _ADG_OLD_ENTITY_CLASS->global_changed(entity);
243 _adg_refresh_extents((AdgText *) entity);
246 static void
247 _adg_local_changed(AdgEntity *entity)
249 if (_ADG_OLD_ENTITY_CLASS->local_changed != NULL)
250 _ADG_OLD_ENTITY_CLASS->local_changed(entity);
252 _adg_refresh_extents((AdgText *) entity);
255 static void
256 _adg_invalidate(AdgEntity *entity)
258 _adg_clear_layout((AdgText *) entity);
260 if (_ADG_OLD_ENTITY_CLASS->invalidate)
261 _ADG_OLD_ENTITY_CLASS->invalidate(entity);
264 static void
265 _adg_arrange(AdgEntity *entity)
267 AdgText *text;
268 AdgTextPrivate *data;
269 PangoRectangle size;
270 AdgMatrix map;
272 text = (AdgText *) entity;
273 data = text->data;
275 if (adg_is_string_empty(data->text)) {
276 /* Undefined text */
277 CpmlExtents new_extents;
278 new_extents.is_defined = FALSE;
279 adg_entity_set_extents(entity, &new_extents);
280 return;
281 } else if (data->layout != NULL) {
282 /* Cached result */
283 return;
286 if (data->layout == NULL) {
287 AdgDress dress;
288 AdgPangoStyle *pango_style;
289 PangoFontMap *font_map;
290 PangoFontDescription *font_description;
291 cairo_font_options_t *options;
292 PangoContext *context;
294 dress = data->font_dress;
295 pango_style = (AdgPangoStyle *) adg_entity_style(entity, dress);
296 font_map = pango_cairo_font_map_new();
297 font_description = adg_pango_style_get_description(pango_style);
299 context = pango_context_new();
300 pango_context_set_font_map(context, font_map);
301 g_object_unref(font_map);
302 pango_cairo_context_set_resolution(context, 72);
304 options = adg_font_style_new_options((AdgFontStyle *) pango_style);
305 pango_cairo_context_set_font_options(context, options);
306 cairo_font_options_destroy(options);
308 data->layout = pango_layout_new(context);
309 g_object_unref(context);
311 pango_layout_set_text(data->layout, data->text, -1);
312 pango_layout_set_font_description(data->layout, font_description);
315 pango_layout_get_extents(data->layout, &size, NULL);
317 data->raw_extents.org.x = pango_units_to_double(size.x);
318 data->raw_extents.org.y = pango_units_to_double(size.y);
319 data->raw_extents.size.x = pango_units_to_double(size.width);
320 data->raw_extents.size.y = pango_units_to_double(size.height);
321 data->raw_extents.is_defined = TRUE;
323 /* Realign the text modifying the local matrix to use the cairo
324 * toy text convention: bottom/left corner is the reference point.
325 * Furthermore, by emitting a "local-changed" signal, the
326 * extents will be automatically updated. */
327 cairo_matrix_init_translate(&map, 0, - data->raw_extents.size.y);
328 adg_entity_transform_local_map(entity, &map, ADG_TRANSFORM_AFTER);
331 static void
332 _adg_render(AdgEntity *entity, cairo_t *cr)
334 AdgText *text;
335 AdgTextPrivate *data;
337 text = (AdgText *) entity;
338 data = text->data;
340 if (data->layout != NULL) {
341 AdgMatrix ctm;
342 adg_entity_apply_dress(entity, data->font_dress, cr);
343 cairo_transform(cr, adg_entity_get_global_matrix(entity));
344 cairo_transform(cr, adg_entity_get_local_matrix(entity));
345 pango_cairo_update_layout(cr, data->layout);
346 pango_cairo_show_layout(cr, data->layout);
350 static void
351 _adg_set_font_dress(AdgTextual *textual, AdgDress dress)
353 g_object_set(textual, "font-dress", dress, NULL);
356 static AdgDress
357 _adg_get_font_dress(AdgTextual *textual)
359 AdgTextPrivate *data = ((AdgText *) textual)->data;
360 return data->font_dress;
363 static void
364 _adg_set_text(AdgTextual *textual, const gchar *text)
366 g_object_set(textual, "text", text, NULL);
369 static gchar *
370 _adg_dup_text(AdgTextual *textual)
372 AdgTextPrivate *data = ((AdgText *) textual)->data;
373 return g_strdup(data->text);
376 static void
377 _adg_refresh_extents(AdgText *text)
379 AdgTextPrivate *data;
380 AdgEntity *entity;
381 AdgMatrix ctm;
382 CpmlExtents new_extents;
384 data = text->data;
386 if (! data->raw_extents.is_defined)
387 return;
389 entity = (AdgEntity *) text;
391 adg_matrix_copy(&ctm, adg_entity_get_global_matrix(entity));
392 adg_matrix_transform(&ctm, adg_entity_get_local_matrix(entity),
393 ADG_TRANSFORM_AFTER);
394 cpml_extents_copy(&new_extents, &data->raw_extents);
395 cpml_pair_transform(&new_extents.org, &ctm);
396 adg_entity_set_extents(entity, &new_extents);
399 static void
400 _adg_clear_layout(AdgText *text)
402 AdgTextPrivate *data = text->data;
404 if (data->layout != NULL) {
405 g_object_unref(data->layout);
406 data->layout = NULL;