[AdgToyText] get_local_matrix() -> local_changed()
[adg.git] / adg / adg-toy-text.c
blobf5cb5c831fa7a9d053b62e3244d6ba1e73920a14
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-type-builtins.h"
42 #include "adg-intl.h"
44 #define PARENT_OBJECT_CLASS ((GObjectClass *) adg_toy_text_parent_class)
45 #define PARENT_ENTITY_CLASS ((AdgEntityClass *) adg_toy_text_parent_class)
48 enum {
49 PROP_0,
50 PROP_DRESS,
51 PROP_LABEL
55 static void finalize (GObject *object);
56 static void get_property (GObject *object,
57 guint param_id,
58 GValue *value,
59 GParamSpec *pspec);
60 static void set_property (GObject *object,
61 guint param_id,
62 const GValue *value,
63 GParamSpec *pspec);
64 static void local_changed (AdgEntity *entity);
65 static void invalidate (AdgEntity *entity);
66 static void render (AdgEntity *entity,
67 cairo_t *cr);
68 static gboolean set_label (AdgToyText *toy_text,
69 const gchar *label);
70 static void update_label_cache (AdgToyText *toy_text,
71 cairo_t *cr);
72 static void clear_label_cache (AdgToyText *toy_text);
75 G_DEFINE_TYPE(AdgToyText, adg_toy_text, ADG_TYPE_ENTITY);
78 static void
79 adg_toy_text_class_init(AdgToyTextClass *klass)
81 GObjectClass *gobject_class;
82 AdgEntityClass *entity_class;
83 GParamSpec *param;
85 gobject_class = (GObjectClass *) klass;
86 entity_class = (AdgEntityClass *) klass;
88 g_type_class_add_private(klass, sizeof(AdgToyTextPrivate));
90 gobject_class->finalize = finalize;
91 gobject_class->get_property = get_property;
92 gobject_class->set_property = set_property;
94 entity_class->local_changed = local_changed;
95 entity_class->invalidate = invalidate;
96 entity_class->render = render;
98 param = adg_param_spec_dress("dress",
99 P_("Font Dress"),
100 P_("The font dress to use for rendering this text"),
101 ADG_DRESS_TEXT_REGULAR,
102 G_PARAM_READWRITE);
103 g_object_class_install_property(gobject_class, PROP_DRESS, param);
105 param = g_param_spec_string("label",
106 P_("Label"),
107 P_("The label to display"),
108 NULL,
109 G_PARAM_READWRITE);
110 g_object_class_install_property(gobject_class, PROP_LABEL, param);
113 static void
114 adg_toy_text_init(AdgToyText *toy_text)
116 AdgToyTextPrivate *data = G_TYPE_INSTANCE_GET_PRIVATE(toy_text,
117 ADG_TYPE_TOY_TEXT,
118 AdgToyTextPrivate);
120 data->dress = ADG_DRESS_TEXT_REGULAR;
121 data->label = NULL;
122 data->glyphs = NULL;
124 toy_text->data = data;
127 static void
128 finalize(GObject *object)
130 AdgToyText *toy_text;
131 AdgToyTextPrivate *data;
133 toy_text = (AdgToyText *) object;
134 data = toy_text->data;
136 g_free(data->label);
137 clear_label_cache(toy_text);
139 if (PARENT_OBJECT_CLASS->finalize != NULL)
140 PARENT_OBJECT_CLASS->finalize(object);
143 static void
144 get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
146 AdgToyTextPrivate *data = ((AdgToyText *) object)->data;
148 switch (prop_id) {
149 case PROP_DRESS:
150 g_value_set_int(value, data->dress);
151 break;
152 case PROP_LABEL:
153 g_value_set_string(value, data->label);
154 break;
155 default:
156 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
157 break;
161 static void
162 set_property(GObject *object, guint prop_id,
163 const GValue *value, GParamSpec *pspec)
165 AdgToyText *toy_text;
166 AdgToyTextPrivate *data;
168 toy_text = (AdgToyText *) object;
169 data = toy_text->data;
171 switch (prop_id) {
172 case PROP_DRESS:
173 adg_dress_set(&data->dress, g_value_get_int(value));
174 break;
175 case PROP_LABEL:
176 set_label(toy_text, g_value_get_string(value));
177 break;
178 default:
179 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
180 break;
186 * adg_toy_text_new:
187 * @label: the label text
189 * Creates a new toy text entity using @label as its text
191 * Returns: the newly created toy text entity
193 AdgToyText *
194 adg_toy_text_new(const gchar *label)
196 return g_object_new(ADG_TYPE_TOY_TEXT, "label", label, NULL);
200 * adg_toy_text_get_dress:
201 * @toy_text: an #AdgToyText
203 * Gets the font dress to be used in rendering @toy_text.
205 * Returns: the current font dress
207 AdgDress
208 adg_toy_text_get_dress(AdgToyText *toy_text)
210 AdgToyTextPrivate *data;
212 g_return_val_if_fail(ADG_IS_TOY_TEXT(toy_text), ADG_DRESS_UNDEFINED);
214 data = toy_text->data;
216 return data->dress;
220 * adg_toy_text_set_dress:
221 * @toy_text: an #AdgToyText
222 * @dress: the new #AdgDress to use
224 * Sets a new font dress for rendering @toy_text. The new dress
225 * must be related to the original dress for this property:
226 * you cannot set a dress used for line styles to a dress
227 * managing fonts.
229 * The check is done by calling adg_dress_are_related() with
230 * @dress and the previous dress as arguments. Check out its
231 * documentation for details on what is a related dress.
233 void
234 adg_toy_text_set_dress(AdgToyText *toy_text, AdgDress dress)
236 AdgToyTextPrivate *data;
238 g_return_if_fail(ADG_IS_TOY_TEXT(toy_text));
240 data = toy_text->data;
242 if (adg_dress_set(&data->dress, dress))
243 g_object_notify((GObject *) toy_text, "dress");
247 * adg_toy_text_get_label:
248 * @toy_text: an #AdgToyText
250 * Gets the label text. The string is internally owned and
251 * must not be freed or modified.
253 * Returns: the label text
255 const gchar *
256 adg_toy_text_get_label(AdgToyText *toy_text)
258 AdgToyTextPrivate *data;
260 g_return_val_if_fail(ADG_IS_TOY_TEXT(toy_text), NULL);
262 data = toy_text->data;
264 return data->label;
268 * adg_toy_text_set_label:
269 * @toy_text: an #AdgToyText
270 * @label: the label text
272 * Sets a new label for @toy_text. @label can be also %NULL,
273 * in which case will be treated as an empty string.
275 void
276 adg_toy_text_set_label(AdgToyText *toy_text, const gchar *label)
278 g_return_if_fail(ADG_IS_TOY_TEXT(toy_text));
280 if (set_label(toy_text, label))
281 g_object_notify((GObject *) toy_text, "label");
285 * adg_toy_text_get_extents:
286 * @toy_text: an #AdgToyText
287 * @cr: a cairo context
288 * @extents: where to store the extents
290 * Computes the extents of @toy_text and returns the result in @extents.
291 * The cairo context is required for font computation.
293 void
294 adg_toy_text_get_extents(AdgToyText *toy_text, cairo_t *cr,
295 cairo_text_extents_t *extents)
297 AdgToyTextPrivate *data;
299 g_return_if_fail(ADG_IS_TOY_TEXT(toy_text));
300 g_return_if_fail(extents != NULL);
302 update_label_cache(toy_text, cr);
304 data = toy_text->data;
305 *extents = data->extents;
309 static void
310 local_changed(AdgEntity *entity)
312 AdgMatrix matrix;
314 PARENT_ENTITY_CLASS->local_changed(entity);
316 adg_entity_get_local_matrix(entity, &matrix);
317 cairo_matrix_init_translate(&matrix, matrix.x0, matrix.y0);
318 adg_entity_set_local_matrix(entity, &matrix);
321 static void
322 invalidate(AdgEntity *entity)
324 clear_label_cache((AdgToyText *) entity);
326 if (PARENT_ENTITY_CLASS->invalidate != NULL)
327 return PARENT_ENTITY_CLASS->invalidate(entity);
330 static void
331 render(AdgEntity *entity, cairo_t *cr)
333 AdgToyText *toy_text;
334 AdgToyTextPrivate *data;
336 toy_text = (AdgToyText *) entity;
337 data = toy_text->data;
339 if (data->label != NULL && data->label[0] != '\0') {
340 update_label_cache(toy_text, cr);
342 cairo_save(cr);
343 adg_entity_apply_local_matrix(entity, cr);
344 cairo_show_glyphs(cr, data->glyphs, data->num_glyphs);
345 cairo_restore(cr);
350 static gboolean
351 set_label(AdgToyText *toy_text, const gchar *label)
353 AdgToyTextPrivate *data = toy_text->data;
355 /* Check if the new label differs from the current label */
356 if (adg_strcmp(label, data->label) == 0)
357 return FALSE;
359 g_free(data->label);
360 data->label = g_strdup(label);
362 clear_label_cache(toy_text);
363 return TRUE;
366 static void
367 update_label_cache(AdgToyText *toy_text, cairo_t *cr)
369 AdgToyTextPrivate *data;
370 cairo_status_t status;
372 data = toy_text->data;
374 adg_entity_apply_dress((AdgEntity *) toy_text, data->dress, cr);
376 if (data->glyphs != NULL)
377 return;
379 status = cairo_scaled_font_text_to_glyphs(cairo_get_scaled_font(cr),
380 0, 0, data->label, -1,
381 &data->glyphs,
382 &data->num_glyphs,
383 NULL, NULL, NULL);
385 if (status != CAIRO_STATUS_SUCCESS) {
386 clear_label_cache(toy_text);
387 g_error("Unable to build glyphs (cairo message: %s)",
388 cairo_status_to_string(status));
389 return;
392 cairo_glyph_extents(cr, data->glyphs, data->num_glyphs, &data->extents);
395 static void
396 clear_label_cache(AdgToyText *toy_text)
398 AdgToyTextPrivate *data = toy_text->data;
400 if (data->glyphs != NULL) {
401 cairo_glyph_free(data->glyphs);
402 data->glyphs = NULL;
405 data->num_glyphs = 0;
406 memset(&data->extents, 0, sizeof(data->extents));