[AdgEntity] Removed adg_entity_ctm()
[adg.git] / adg / adg-toy-text.c
blob259237f120d32f5032e730b80f9ab8d40f9376f6
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.
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-toy-text.h"
40 #include "adg-toy-text-private.h"
41 #include "adg-dress-builtins.h"
42 #include "adg-font-style.h"
43 #include "adg-intl.h"
45 #define PARENT_OBJECT_CLASS ((GObjectClass *) adg_toy_text_parent_class)
46 #define PARENT_ENTITY_CLASS ((AdgEntityClass *) adg_toy_text_parent_class)
49 enum {
50 PROP_0,
51 PROP_FONT_DRESS,
52 PROP_LABEL
56 static void finalize (GObject *object);
57 static void get_property (GObject *object,
58 guint param_id,
59 GValue *value,
60 GParamSpec *pspec);
61 static void set_property (GObject *object,
62 guint param_id,
63 const GValue *value,
64 GParamSpec *pspec);
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,
70 cairo_t *cr);
71 static gboolean set_font_dress (AdgToyText *toy_text,
72 AdgDress dress);
73 static gboolean set_label (AdgToyText *toy_text,
74 const gchar *label);
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);
82 static void
83 adg_toy_text_class_init(AdgToyTextClass *klass)
85 GObjectClass *gobject_class;
86 AdgEntityClass *entity_class;
87 GParamSpec *param;
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",
105 P_("Font Dress"),
106 P_("The font dress to use for rendering this text"),
107 ADG_DRESS_TEXT,
108 G_PARAM_READWRITE);
109 g_object_class_install_property(gobject_class, PROP_FONT_DRESS, param);
111 param = g_param_spec_string("label",
112 P_("Label"),
113 P_("The label to display"),
114 NULL,
115 G_PARAM_READWRITE);
116 g_object_class_install_property(gobject_class, PROP_LABEL, param);
119 static void
120 adg_toy_text_init(AdgToyText *toy_text)
122 AdgToyTextPrivate *data = G_TYPE_INSTANCE_GET_PRIVATE(toy_text,
123 ADG_TYPE_TOY_TEXT,
124 AdgToyTextPrivate);
126 data->font_dress = ADG_DRESS_TEXT;
127 data->label = NULL;
128 data->glyphs = NULL;
130 toy_text->data = data;
133 static void
134 finalize(GObject *object)
136 AdgToyText *toy_text;
137 AdgToyTextPrivate *data;
139 toy_text = (AdgToyText *) object;
140 data = toy_text->data;
142 g_free(data->label);
143 unset_font(toy_text);
144 unset_glyphs(toy_text);
146 if (PARENT_OBJECT_CLASS->finalize)
147 PARENT_OBJECT_CLASS->finalize(object);
150 static void
151 get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
153 AdgToyTextPrivate *data = ((AdgToyText *) object)->data;
155 switch (prop_id) {
156 case PROP_FONT_DRESS:
157 g_value_set_int(value, data->font_dress);
158 break;
159 case PROP_LABEL:
160 g_value_set_string(value, data->label);
161 break;
162 default:
163 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
164 break;
168 static void
169 set_property(GObject *object, guint prop_id,
170 const GValue *value, GParamSpec *pspec)
172 AdgToyText *toy_text = (AdgToyText *) object;
174 switch (prop_id) {
175 case PROP_FONT_DRESS:
176 set_font_dress(toy_text, g_value_get_int(value));
177 break;
178 case PROP_LABEL:
179 set_label(toy_text, g_value_get_string(value));
180 break;
181 default:
182 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
183 break;
189 * adg_toy_text_new:
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
198 AdgToyText *
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
214 AdgDress
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
234 * managing fonts.
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.
240 void
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
258 const gchar *
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;
267 return data->label;
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.
278 void
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");
288 static void
289 global_changed(AdgEntity *entity)
291 AdgMatrix old;
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);
307 static void
308 local_changed(AdgEntity *entity)
310 AdgMatrix old;
311 const AdgMatrix *new;
312 CpmlExtents extents;
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_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);
338 static void
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);
348 static void
349 arrange(AdgEntity *entity)
351 AdgToyText *toy_text;
352 AdgToyTextPrivate *data;
353 CpmlExtents extents;
355 toy_text = (AdgToyText *) entity;
356 data = toy_text->data;
358 if (data->font == NULL) {
359 AdgDress dress;
360 AdgFontStyle *font_style;
361 AdgMatrix ctm;
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) {
377 /* Cached result */
378 return;
379 } else {
380 cairo_status_t status;
381 cairo_text_extents_t cairo_extents;
383 status = cairo_scaled_font_text_to_glyphs(data->font, 0, 0,
384 data->label, -1,
385 &data->glyphs,
386 &data->num_glyphs,
387 NULL, NULL, NULL);
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));
393 return;
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);
406 static void
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);
422 static gboolean
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);
429 return TRUE;
432 return FALSE;
435 static gboolean
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)
442 return FALSE;
444 g_free(data->label);
445 data->label = g_strdup(label);
447 unset_glyphs(toy_text);
448 return TRUE;
451 static void
452 unset_font(AdgToyText *toy_text)
454 AdgToyTextPrivate *data = toy_text->data;
456 data->font = NULL;
459 static void
460 unset_glyphs(AdgToyText *toy_text)
462 AdgToyTextPrivate *data = toy_text->data;
464 if (data->glyphs != NULL) {
465 cairo_glyph_free(data->glyphs);
466 data->glyphs = NULL;
469 data->num_glyphs = 0;