[AdgMarker] Using a custom local matrix
[adg.git] / adg / adg-toy-text.c
blob70ff67860d0fd74f353b01c266b11f8a10958f62
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-font-style.h"
42 #include "adg-type-builtins.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_LABEL,
52 PROP_FONT_STYLE
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 get_local_matrix (AdgEntity *entity,
66 AdgMatrix *matrix);
67 static gboolean invalidate (AdgEntity *entity);
68 static gboolean render (AdgEntity *entity,
69 cairo_t *cr);
70 static gboolean set_label (AdgToyText *toy_text,
71 const gchar *label);
72 static gboolean set_font_style (AdgToyText *toy_text,
73 AdgFontStyleId font_style);
74 static void update_label_cache (AdgToyText *toy_text,
75 cairo_t *cr);
76 static void clear_label_cache (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->get_local_matrix = get_local_matrix;
99 entity_class->invalidate = invalidate;
100 entity_class->render = render;
102 param = g_param_spec_string("label",
103 P_("Label"),
104 P_("The label to display"),
105 NULL, G_PARAM_READWRITE);
106 g_object_class_install_property(gobject_class, PROP_LABEL, param);
108 param = g_param_spec_enum("font-style",
109 P_("Font Style"),
110 P_("The identifier of the font to use while rendering the label"),
111 ADG_TYPE_FONT_STYLE_ID,
112 ADG_FONT_STYLE_TEXT,
113 G_PARAM_READWRITE);
114 g_object_class_install_property(gobject_class, PROP_FONT_STYLE, param);
117 static void
118 adg_toy_text_init(AdgToyText *toy_text)
120 AdgToyTextPrivate *data = G_TYPE_INSTANCE_GET_PRIVATE(toy_text,
121 ADG_TYPE_TOY_TEXT,
122 AdgToyTextPrivate);
124 data->label = NULL;
125 data->font_style = ADG_FONT_STYLE_TEXT;
126 data->glyphs = NULL;
128 toy_text->data = data;
131 static void
132 finalize(GObject *object)
134 AdgToyText *toy_text;
135 AdgToyTextPrivate *data;
137 toy_text = (AdgToyText *) object;
138 data = toy_text->data;
140 g_free(data->label);
141 clear_label_cache(toy_text);
143 if (PARENT_OBJECT_CLASS->finalize != NULL)
144 PARENT_OBJECT_CLASS->finalize(object);
147 static void
148 get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
150 AdgToyTextPrivate *data = ((AdgToyText *) object)->data;
152 switch (prop_id) {
153 case PROP_LABEL:
154 g_value_set_string(value, data->label);
155 break;
156 case PROP_FONT_STYLE:
157 g_value_set_enum(value, data->font_style);
158 break;
159 default:
160 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
161 break;
165 static void
166 set_property(GObject *object, guint prop_id,
167 const GValue *value, GParamSpec *pspec)
169 AdgToyText *toy_text = (AdgToyText *) object;
171 switch (prop_id) {
172 case PROP_LABEL:
173 set_label(toy_text, g_value_get_string(value));
174 break;
175 case PROP_FONT_STYLE:
176 set_font_style(toy_text, g_value_get_enum(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_label:
201 * @toy_text: an #AdgToyText
203 * Gets the label text. The string is internally owned and
204 * must not be freed or modified.
206 * Returns: the label text
208 const gchar *
209 adg_toy_text_get_label(AdgToyText *toy_text)
211 AdgToyTextPrivate *data;
213 g_return_val_if_fail(ADG_IS_TOY_TEXT(toy_text), NULL);
215 data = toy_text->data;
217 return data->label;
221 * adg_toy_text_set_label:
222 * @toy_text: an #AdgToyText
223 * @label: the label text
225 * Sets a new label for @toy_text. @label can be also %NULL,
226 * in which case will be treated as an empty string.
228 void
229 adg_toy_text_set_label(AdgToyText *toy_text, const gchar *label)
231 g_return_if_fail(ADG_IS_TOY_TEXT(toy_text));
233 if (set_label(toy_text, label))
234 g_object_notify((GObject *) toy_text, "label");
238 * adg_toy_text_get_font_style:
239 * @toy_text: an #AdgToyText
241 * Gets the font style id of this label.
243 * Returns: the font id
245 const AdgFontStyleId
246 adg_toy_text_get_font_style(AdgToyText *toy_text)
248 AdgToyTextPrivate *data;
250 g_return_val_if_fail(ADG_IS_TOY_TEXT(toy_text), ADG_FONT_STYLE_TEXT);
252 data = toy_text->data;
254 return data->font_style;
258 * adg_toy_text_set_font_style:
259 * @toy_text: an #AdgToyText
260 * @font_style: the new font style id to use
262 * Sets a new font style for @toy_text.
264 void
265 adg_toy_text_set_font_style(AdgToyText *toy_text, AdgFontStyleId font_style)
267 g_return_if_fail(ADG_IS_TOY_TEXT(toy_text));
269 if (set_font_style(toy_text, font_style))
270 g_object_notify((GObject *) toy_text, "font-style");
274 * adg_toy_text_get_extents:
275 * @toy_text: an #AdgToyText
276 * @cr: a cairo context
277 * @extents: where to store the extents
279 * Computes the extents of @toy_text and returns the result in @extents.
280 * The cairo context is required for font computation.
282 void
283 adg_toy_text_get_extents(AdgToyText *toy_text, cairo_t *cr,
284 cairo_text_extents_t *extents)
286 AdgToyTextPrivate *data;
288 g_return_if_fail(ADG_IS_TOY_TEXT(toy_text));
289 g_return_if_fail(extents != NULL);
291 update_label_cache(toy_text, cr);
293 data = toy_text->data;
294 *extents = data->extents;
298 static void
299 get_local_matrix(AdgEntity *entity, AdgMatrix *matrix)
301 PARENT_ENTITY_CLASS->get_local_matrix(entity, matrix);
302 cairo_matrix_init_translate(matrix, matrix->x0, matrix->y0);
305 static gboolean
306 invalidate(AdgEntity *entity)
308 clear_label_cache((AdgToyText *) entity);
310 if (PARENT_ENTITY_CLASS->invalidate != NULL)
311 return PARENT_ENTITY_CLASS->invalidate(entity);
313 return TRUE;
316 static gboolean
317 render(AdgEntity *entity, cairo_t *cr)
319 AdgToyText *toy_text;
320 AdgToyTextPrivate *data;
322 toy_text = (AdgToyText *) entity;
323 data = toy_text->data;
325 if (data->label != NULL && data->label[0] != '\0') {
326 update_label_cache(toy_text, cr);
328 cairo_save(cr);
329 adg_entity_apply_local_matrix(entity, cr);
330 cairo_show_glyphs(cr, data->glyphs, data->num_glyphs);
331 cairo_restore(cr);
334 return TRUE;
338 static gboolean
339 set_label(AdgToyText *toy_text, const gchar *label)
341 AdgToyTextPrivate *data = toy_text->data;
343 /* Check if the new label differs from the current label */
344 if (adg_strcmp(label, data->label) == 0)
345 return FALSE;
347 g_free(data->label);
348 data->label = g_strdup(label);
350 clear_label_cache(toy_text);
351 return TRUE;
354 static gboolean
355 set_font_style(AdgToyText *toy_text, AdgFontStyleId font_style)
357 AdgToyTextPrivate *data = toy_text->data;
359 /* Check if the new style differs from the current one */
360 if (font_style == data->font_style)
361 return FALSE;
363 data->font_style = font_style;
365 /* Changing the font invalidate the cache */
366 clear_label_cache(toy_text);
367 return TRUE;
370 static void
371 update_label_cache(AdgToyText *toy_text, cairo_t *cr)
373 AdgToyTextPrivate *data;
374 cairo_status_t status;
376 data = toy_text->data;
378 adg_entity_apply_font((AdgEntity *) toy_text, data->font_style, cr);
380 if (data->glyphs != NULL)
381 return;
383 status = cairo_scaled_font_text_to_glyphs(cairo_get_scaled_font(cr),
384 0, 0, data->label, -1,
385 &data->glyphs,
386 &data->num_glyphs,
387 NULL, NULL, NULL);
389 if (status != CAIRO_STATUS_SUCCESS) {
390 clear_label_cache(toy_text);
391 g_error("Unable to build glyphs (cairo message: %s)",
392 cairo_status_to_string(status));
393 return;
396 cairo_glyph_extents(cr, data->glyphs, data->num_glyphs, &data->extents);
399 static void
400 clear_label_cache(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;
410 memset(&data->extents, 0, sizeof(data->extents));