[AdgModel] Enhanced docs
[adg.git] / adg / adg-toy-text.c
blobb87fd39e4f10adb75ef77a033d1df42e144dcadb
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.
27 **/
29 /**
30 * AdgToyText:
32 * All fields are privates and should not be used directly.
33 * Use its public methods instead.
34 **/
37 #include "adg-toy-text.h"
38 #include "adg-toy-text-private.h"
39 #include "adg-font-style.h"
40 #include "adg-type-builtins.h"
41 #include "adg-intl.h"
43 #define PARENT_OBJECT_CLASS ((GObjectClass *) adg_toy_text_parent_class)
44 #define PARENT_ENTITY_CLASS ((AdgEntityClass *) adg_toy_text_parent_class)
47 enum {
48 PROP_0,
49 PROP_LABEL,
50 PROP_FONT_STYLE
54 static void finalize (GObject *object);
55 static void get_property (GObject *object,
56 guint param_id,
57 GValue *value,
58 GParamSpec *pspec);
59 static void set_property (GObject *object,
60 guint param_id,
61 const GValue *value,
62 GParamSpec *pspec);
63 static gboolean invalidate (AdgEntity *entity);
64 static gboolean render (AdgEntity *entity,
65 cairo_t *cr);
66 static gboolean set_label (AdgToyText *toy_text,
67 const gchar *label);
68 static gboolean set_font_style (AdgToyText *toy_text,
69 AdgFontStyleId font_style);
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->invalidate = invalidate;
95 entity_class->render = render;
97 param = g_param_spec_string("label",
98 P_("Label"),
99 P_("The label to display"),
100 NULL, G_PARAM_READWRITE);
101 g_object_class_install_property(gobject_class, PROP_LABEL, param);
103 param = g_param_spec_enum("font-style",
104 P_("Font Style"),
105 P_("The identifier of the font to use while rendering the label"),
106 ADG_TYPE_FONT_STYLE_ID,
107 ADG_FONT_STYLE_TEXT,
108 G_PARAM_READWRITE);
109 g_object_class_install_property(gobject_class, PROP_FONT_STYLE, param);
112 static void
113 adg_toy_text_init(AdgToyText *toy_text)
115 AdgToyTextPrivate *data = G_TYPE_INSTANCE_GET_PRIVATE(toy_text,
116 ADG_TYPE_TOY_TEXT,
117 AdgToyTextPrivate);
119 data->label = NULL;
120 data->font_style = ADG_FONT_STYLE_TEXT;
121 data->glyphs = NULL;
123 toy_text->data = data;
126 static void
127 finalize(GObject *object)
129 AdgToyText *toy_text;
130 AdgToyTextPrivate *data;
132 toy_text = (AdgToyText *) object;
133 data = toy_text->data;
135 g_free(data->label);
136 clear_label_cache(toy_text);
138 if (PARENT_OBJECT_CLASS->finalize != NULL)
139 PARENT_OBJECT_CLASS->finalize(object);
142 static void
143 get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
145 AdgToyTextPrivate *data = ((AdgToyText *) object)->data;
147 switch (prop_id) {
148 case PROP_LABEL:
149 g_value_set_string(value, data->label);
150 break;
151 case PROP_FONT_STYLE:
152 g_value_set_enum(value, data->font_style);
153 break;
154 default:
155 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
156 break;
160 static void
161 set_property(GObject *object, guint prop_id,
162 const GValue *value, GParamSpec *pspec)
164 AdgToyText *toy_text = (AdgToyText *) object;
166 switch (prop_id) {
167 case PROP_LABEL:
168 set_label(toy_text, g_value_get_string(value));
169 break;
170 case PROP_FONT_STYLE:
171 set_font_style(toy_text, g_value_get_enum(value));
172 break;
173 default:
174 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
175 break;
181 * adg_toy_text_new:
182 * @label: the label text
184 * Creates a new toy text entity using @label as its text
186 * Returns: the new entity
188 AdgEntity *
189 adg_toy_text_new(const gchar *label)
191 return (AdgEntity *) g_object_new(ADG_TYPE_TOY_TEXT, "label", label, NULL);
195 * adg_toy_text_get_label:
196 * @toy_text: an #AdgToyText
198 * Gets the label text. The string is internally owned and
199 * must not be freed or modified.
201 * Returns: the label text
203 const gchar *
204 adg_toy_text_get_label(AdgToyText *toy_text)
206 AdgToyTextPrivate *data;
208 g_return_val_if_fail(ADG_IS_TOY_TEXT(toy_text), NULL);
210 data = toy_text->data;
212 return data->label;
216 * adg_toy_text_set_label:
217 * @toy_text: an #AdgToyText
218 * @label: the label text
220 * Sets a new label for @toy_text. @label can be also %NULL,
221 * in which case will be treated as an empty string.
223 void
224 adg_toy_text_set_label(AdgToyText *toy_text, const gchar *label)
226 g_return_if_fail(ADG_IS_TOY_TEXT(toy_text));
228 if (set_label(toy_text, label))
229 g_object_notify((GObject *) toy_text, "label");
233 * adg_toy_text_get_font_style:
234 * @toy_text: an #AdgToyText
236 * Gets the font style id of this label.
238 * Returns: the font id
240 const AdgFontStyleId
241 adg_toy_text_get_font_style(AdgToyText *toy_text)
243 AdgToyTextPrivate *data;
245 g_return_val_if_fail(ADG_IS_TOY_TEXT(toy_text), ADG_FONT_STYLE_TEXT);
247 data = toy_text->data;
249 return data->font_style;
253 * adg_toy_text_set_font_style:
254 * @toy_text: an #AdgToyText
255 * @font_style: the new font style id to use
257 * Sets a new font style for @toy_text.
259 void
260 adg_toy_text_set_font_style(AdgToyText *toy_text, AdgFontStyleId font_style)
262 g_return_if_fail(ADG_IS_TOY_TEXT(toy_text));
264 if (set_font_style(toy_text, font_style))
265 g_object_notify((GObject *) toy_text, "font-style");
269 * adg_toy_text_get_extents:
270 * @toy_text: an #AdgToyText
271 * @cr: a cairo context
272 * @extents: where to store the extents
274 * Computes the extents of @toy_text and returns the result in @extents.
275 * The cairo context is required for font computation.
277 void
278 adg_toy_text_get_extents(AdgToyText *toy_text, cairo_t *cr,
279 cairo_text_extents_t *extents)
281 AdgToyTextPrivate *data;
283 g_return_if_fail(ADG_IS_TOY_TEXT(toy_text));
284 g_return_if_fail(extents != NULL);
286 update_label_cache(toy_text, cr);
288 data = toy_text->data;
289 *extents = data->extents;
293 static gboolean
294 invalidate(AdgEntity *entity)
296 clear_label_cache((AdgToyText *) entity);
298 if (PARENT_ENTITY_CLASS->invalidate != NULL)
299 return PARENT_ENTITY_CLASS->invalidate(entity);
301 return TRUE;
304 static gboolean
305 render(AdgEntity *entity, cairo_t *cr)
307 AdgToyText *toy_text;
308 AdgToyTextPrivate *data;
310 toy_text = (AdgToyText *) entity;
311 data = toy_text->data;
313 if (data->label != NULL && data->label[0] != '\0') {
314 AdgMatrix ctm, org;
316 adg_entity_get_local_matrix(entity, &org);
317 cairo_matrix_init_translate(&org, org.x0, org.y0);
319 update_label_cache(toy_text, cr);
321 cairo_save(cr);
323 /* Apply the org displacement BEFORE the global matrix */
324 cairo_get_matrix(cr, &ctm);
325 cairo_matrix_multiply(&ctm, &ctm, &org);
326 cairo_set_matrix(cr, &ctm);
328 cairo_show_glyphs(cr, data->glyphs, data->num_glyphs);
329 cairo_restore(cr);
332 return TRUE;
336 static gboolean
337 set_label(AdgToyText *toy_text, const gchar *label)
339 AdgToyTextPrivate *data = toy_text->data;
341 /* Check if the new label differs from the current label */
342 if (adg_strcmp(label, data->label) == 0)
343 return FALSE;
345 g_free(data->label);
346 data->label = g_strdup(label);
348 clear_label_cache(toy_text);
349 return TRUE;
352 static gboolean
353 set_font_style(AdgToyText *toy_text, AdgFontStyleId font_style)
355 AdgToyTextPrivate *data = toy_text->data;
357 /* Check if the new style differs from the current one */
358 if (font_style == data->font_style)
359 return FALSE;
361 data->font_style = font_style;
363 /* Changing the font invalidate the cache */
364 clear_label_cache(toy_text);
365 return TRUE;
368 static void
369 update_label_cache(AdgToyText *toy_text, cairo_t *cr)
371 AdgToyTextPrivate *data;
372 cairo_status_t status;
374 data = toy_text->data;
376 adg_entity_apply_font((AdgEntity *) toy_text, data->font_style, cr);
378 if (data->glyphs != NULL)
379 return;
381 status = cairo_scaled_font_text_to_glyphs(cairo_get_scaled_font(cr),
382 0, 0, data->label, -1,
383 &data->glyphs,
384 &data->num_glyphs,
385 NULL, NULL, NULL);
387 if (status != CAIRO_STATUS_SUCCESS) {
388 clear_label_cache(toy_text);
389 g_error("Unable to build glyphs (cairo message: %s)",
390 cairo_status_to_string(status));
391 return;
394 cairo_glyph_extents(cr, data->glyphs, data->num_glyphs, &data->extents);
397 static void
398 clear_label_cache(AdgToyText *toy_text)
400 AdgToyTextPrivate *data = toy_text->data;
402 if (data->glyphs != NULL) {
403 cairo_glyph_free(data->glyphs);
404 data->glyphs = NULL;
407 data->num_glyphs = 0;
408 memset(&data->extents, 0, sizeof(data->extents));