s/2010 N/2010,2011 N/
[adg.git] / src / adg / adg-toy-text.c
blob9802c7ef9fd5c0b79779824d13bad5bf06249caa
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-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.
29 **/
31 /**
32 * AdgToyText:
34 * All fields are privates and should not be used directly.
35 * Use its public methods instead.
36 **/
39 #include "adg-internal.h"
40 #include "adg-toy-text.h"
41 #include "adg-toy-text-private.h"
42 #include "adg-dress-builtins.h"
43 #include "adg-font-style.h"
45 #define _ADG_OLD_OBJECT_CLASS ((GObjectClass *) adg_toy_text_parent_class)
46 #define _ADG_OLD_ENTITY_CLASS ((AdgEntityClass *) adg_toy_text_parent_class)
49 G_DEFINE_TYPE(AdgToyText, adg_toy_text, ADG_TYPE_ENTITY);
51 enum {
52 PROP_0,
53 PROP_FONT_DRESS,
54 PROP_LABEL
58 static void _adg_finalize (GObject *object);
59 static void _adg_get_property (GObject *object,
60 guint param_id,
61 GValue *value,
62 GParamSpec *pspec);
63 static void _adg_set_property (GObject *object,
64 guint param_id,
65 const GValue *value,
66 GParamSpec *pspec);
67 static void _adg_global_changed (AdgEntity *entity);
68 static void _adg_local_changed (AdgEntity *entity);
69 static void _adg_invalidate (AdgEntity *entity);
70 static void _adg_arrange (AdgEntity *entity);
71 static void _adg_render (AdgEntity *entity,
72 cairo_t *cr);
73 static void _adg_clear_font (AdgToyText *toy_text);
74 static void _adg_clear_glyphs (AdgToyText *toy_text);
77 static void
78 adg_toy_text_class_init(AdgToyTextClass *klass)
80 GObjectClass *gobject_class;
81 AdgEntityClass *entity_class;
82 GParamSpec *param;
84 gobject_class = (GObjectClass *) klass;
85 entity_class = (AdgEntityClass *) klass;
87 g_type_class_add_private(klass, sizeof(AdgToyTextPrivate));
89 gobject_class->finalize = _adg_finalize;
90 gobject_class->get_property = _adg_get_property;
91 gobject_class->set_property = _adg_set_property;
93 entity_class->global_changed = _adg_global_changed;
94 entity_class->local_changed = _adg_local_changed;
95 entity_class->invalidate = _adg_invalidate;
96 entity_class->arrange = _adg_arrange;
97 entity_class->render = _adg_render;
99 param = adg_param_spec_dress("font-dress",
100 P_("Font Dress"),
101 P_("The font dress to use for rendering this text"),
102 ADG_DRESS_FONT_TEXT,
103 G_PARAM_READWRITE);
104 g_object_class_install_property(gobject_class, PROP_FONT_DRESS, param);
106 param = g_param_spec_string("label",
107 P_("Label"),
108 P_("The label to display"),
109 NULL,
110 G_PARAM_READWRITE);
111 g_object_class_install_property(gobject_class, PROP_LABEL, param);
114 static void
115 adg_toy_text_init(AdgToyText *toy_text)
117 AdgToyTextPrivate *data = G_TYPE_INSTANCE_GET_PRIVATE(toy_text,
118 ADG_TYPE_TOY_TEXT,
119 AdgToyTextPrivate);
121 data->font_dress = ADG_DRESS_FONT_TEXT;
122 data->label = NULL;
123 data->glyphs = NULL;
125 toy_text->data = data;
128 static void
129 _adg_finalize(GObject *object)
131 AdgToyText *toy_text;
132 AdgToyTextPrivate *data;
134 toy_text = (AdgToyText *) object;
135 data = toy_text->data;
137 g_free(data->label);
138 _adg_clear_font(toy_text);
139 _adg_clear_glyphs(toy_text);
141 if (_ADG_OLD_OBJECT_CLASS->finalize)
142 _ADG_OLD_OBJECT_CLASS->finalize(object);
145 static void
146 _adg_get_property(GObject *object, guint prop_id,
147 GValue *value, GParamSpec *pspec)
149 AdgToyTextPrivate *data = ((AdgToyText *) object)->data;
151 switch (prop_id) {
152 case PROP_FONT_DRESS:
153 g_value_set_int(value, data->font_dress);
154 break;
155 case PROP_LABEL:
156 g_value_set_string(value, data->label);
157 break;
158 default:
159 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
160 break;
164 static void
165 _adg_set_property(GObject *object, guint prop_id,
166 const GValue *value, GParamSpec *pspec)
168 AdgToyText *toy_text;
169 AdgToyTextPrivate *data;
171 toy_text = (AdgToyText *) object;
172 data = toy_text->data;
174 switch (prop_id) {
175 case PROP_FONT_DRESS:
176 data->font_dress = g_value_get_int(value);
177 _adg_clear_font(toy_text);
178 break;
179 case PROP_LABEL:
180 g_free(data->label);
181 data->label = g_value_dup_string(value);
182 _adg_clear_glyphs(toy_text);
183 break;
184 default:
185 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
186 break;
192 * adg_toy_text_new:
193 * @label: the label text
195 * Creates a new toy text entity using @label as its text. The
196 * #AdgEntity:local-method property is set by default to
197 * #ADG_LOCAL_NORMALIZED.
199 * Returns: the newly created toy text entity
201 AdgToyText *
202 adg_toy_text_new(const gchar *label)
204 return g_object_new(ADG_TYPE_TOY_TEXT,
205 "local-method", ADG_MIX_ANCESTORS_NORMALIZED,
206 "label", label, NULL);
210 * adg_toy_text_set_font_dress:
211 * @toy_text: an #AdgToyText
212 * @dress: the new #AdgDress to use
214 * Sets a new font dress for rendering @toy_text. The new dress
215 * must be related to the original dress for this property:
216 * you cannot set a dress used for line styles to a dress
217 * managing fonts.
219 * The check is done by calling adg_dress_are_related() with
220 * @dress and the previous dress as arguments. Check out its
221 * documentation for details on what is a related dress.
223 void
224 adg_toy_text_set_font_dress(AdgToyText *toy_text, AdgDress dress)
226 g_return_if_fail(ADG_IS_TOY_TEXT(toy_text));
227 g_object_set(toy_text, "font-dress", dress, NULL);
231 * adg_toy_text_get_font_dress:
232 * @toy_text: an #AdgToyText
234 * Gets the font dress to be used in rendering @toy_text.
236 * Returns: the current font dress
238 AdgDress
239 adg_toy_text_get_font_dress(AdgToyText *toy_text)
241 AdgToyTextPrivate *data;
243 g_return_val_if_fail(ADG_IS_TOY_TEXT(toy_text), ADG_DRESS_UNDEFINED);
245 data = toy_text->data;
247 return data->font_dress;
251 * adg_toy_text_set_label:
252 * @toy_text: an #AdgToyText
253 * @label: the label text
255 * Sets a new label for @toy_text. @label can be also %NULL,
256 * in which case will be treated as an empty string.
258 void
259 adg_toy_text_set_label(AdgToyText *toy_text, const gchar *label)
261 g_return_if_fail(ADG_IS_TOY_TEXT(toy_text));
262 g_object_set(toy_text, "label", label, NULL);
266 * adg_toy_text_get_label:
267 * @toy_text: an #AdgToyText
269 * Gets the label text. The string is internally owned and
270 * must not be freed or modified.
272 * Returns: the label text
274 const gchar *
275 adg_toy_text_get_label(AdgToyText *toy_text)
277 AdgToyTextPrivate *data;
279 g_return_val_if_fail(ADG_IS_TOY_TEXT(toy_text), NULL);
281 data = toy_text->data;
283 return data->label;
287 static void
288 _adg_global_changed(AdgEntity *entity)
290 if (_ADG_OLD_ENTITY_CLASS->global_changed)
291 _ADG_OLD_ENTITY_CLASS->global_changed(entity);
293 adg_entity_invalidate(entity);
296 static void
297 _adg_local_changed(AdgEntity *entity)
299 if (_ADG_OLD_ENTITY_CLASS->local_changed)
300 _ADG_OLD_ENTITY_CLASS->local_changed(entity);
302 adg_entity_invalidate(entity);
305 static void
306 _adg_invalidate(AdgEntity *entity)
308 _adg_clear_font((AdgToyText *) entity);
309 _adg_clear_glyphs((AdgToyText *) entity);
311 if (_ADG_OLD_ENTITY_CLASS->invalidate)
312 _ADG_OLD_ENTITY_CLASS->invalidate(entity);
315 static void
316 _adg_arrange(AdgEntity *entity)
318 AdgToyText *toy_text;
319 AdgToyTextPrivate *data;
320 CpmlExtents extents;
322 toy_text = (AdgToyText *) entity;
323 data = toy_text->data;
325 if (data->font == NULL) {
326 AdgDress dress;
327 AdgFontStyle *font_style;
328 AdgMatrix ctm;
330 dress = data->font_dress;
331 font_style = (AdgFontStyle *) adg_entity_style(entity, dress);
333 adg_matrix_copy(&ctm, adg_entity_get_global_matrix(entity));
334 adg_matrix_transform(&ctm, adg_entity_get_local_matrix(entity),
335 ADG_TRANSFORM_BEFORE);
337 data->font = adg_font_style_get_scaled_font(font_style, &ctm);
340 if (adg_is_string_empty(data->label)) {
341 /* Undefined label */
342 extents.is_defined = FALSE;
343 } else if (data->glyphs != NULL) {
344 /* Cached result */
345 return;
346 } else {
347 cairo_status_t status;
348 cairo_text_extents_t cairo_extents;
350 status = cairo_scaled_font_text_to_glyphs(data->font, 0, 0,
351 data->label, -1,
352 &data->glyphs,
353 &data->num_glyphs,
354 NULL, NULL, NULL);
356 if (status != CAIRO_STATUS_SUCCESS) {
357 _adg_clear_glyphs(toy_text);
358 g_error(_("Unable to build glyphs (cairo message: %s)"),
359 cairo_status_to_string(status));
360 return;
363 cairo_scaled_font_glyph_extents(data->font, data->glyphs,
364 data->num_glyphs, &cairo_extents);
365 cpml_extents_from_cairo_text(&extents, &cairo_extents);
366 cpml_extents_transform(&extents, adg_entity_get_local_matrix(entity));
367 cpml_extents_transform(&extents, adg_entity_get_global_matrix(entity));
371 adg_entity_set_extents(entity, &extents);
374 static void
375 _adg_render(AdgEntity *entity, cairo_t *cr)
377 AdgToyText *toy_text;
378 AdgToyTextPrivate *data;
380 toy_text = (AdgToyText *) entity;
381 data = toy_text->data;
383 if (data->glyphs != NULL) {
384 adg_entity_apply_dress(entity, data->font_dress, cr);
385 cairo_transform(cr, adg_entity_get_global_matrix(entity));
386 cairo_transform(cr, adg_entity_get_local_matrix(entity));
387 cairo_show_glyphs(cr, data->glyphs, data->num_glyphs);
391 static void
392 _adg_clear_font(AdgToyText *toy_text)
394 AdgToyTextPrivate *data = toy_text->data;
396 data->font = NULL;
399 static void
400 _adg_clear_glyphs(AdgToyText *toy_text)
402 AdgToyTextPrivate *data = toy_text->data;
404 if (data->glyphs != NULL) {
405 cairo_glyph_free(data->glyphs);
406 data->glyphs = NULL;
409 data->num_glyphs = 0;