[AdgTranslatable] Removed from ADG
[adg.git] / adg / adg-toy-text.c
blobec7474a9f149c4194aab5bd489fe33771cfd0bb2
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 * @title: AdgToyText
24 * @short_description: Simple text entity that use the cairo "toy" text API
26 * The #AdgToyText class is a basic class to show simple text. It internally
27 * uses the so called cairo "toy" API and it shares the same limitations.
28 **/
30 /**
31 * AdgToyText:
33 * All fields are privates and should not be used directly.
34 * Use its public methods instead.
35 **/
38 #include "adg-toy-text.h"
39 #include "adg-toy-text-private.h"
40 #include "adg-rotable.h"
41 #include "adg-font-style.h"
42 #include "adg-intl.h"
45 enum {
46 PROP_0,
47 PROP_ANGLE,
48 PROP_LABEL
51 static void rotable_init (AdgRotableIface*iface);
52 static gdouble get_angle (AdgRotable *rotable);
53 static void set_angle (AdgRotable *rotable,
54 gdouble angle);
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 model_matrix_changed (AdgEntity *entity,
66 AdgMatrix *parent_matrix);
67 static void invalidate (AdgEntity *entity);
68 static void render (AdgEntity *entity,
69 cairo_t *cr);
70 static gboolean update_origin_cache (AdgToyText *toy_text,
71 cairo_t *cr);
72 static gboolean update_label_cache (AdgToyText *toy_text,
73 cairo_t *cr);
74 static void clear_label_cache (AdgToyText *toy_text);
77 G_DEFINE_TYPE_WITH_CODE(AdgToyText, adg_toy_text, ADG_TYPE_ENTITY,
78 G_IMPLEMENT_INTERFACE(ADG_TYPE_ROTABLE, rotable_init))
81 static void
82 rotable_init(AdgRotableIface *iface)
84 iface->get_angle = get_angle;
85 iface->set_angle = set_angle;
88 static gdouble
89 get_angle(AdgRotable *rotable)
91 AdgToyText *toy_text;
92 AdgToyTextPrivate *data;
94 toy_text = (AdgToyText *) rotable;
95 data = toy_text->data;
97 return data->angle;
100 static void
101 set_angle(AdgRotable *rotable, gdouble angle)
103 AdgToyText *toy_text;
104 AdgToyTextPrivate *data;
106 toy_text = (AdgToyText *) rotable;
107 data = toy_text->data;
109 data->angle = angle;
113 static void
114 adg_toy_text_class_init(AdgToyTextClass *klass)
116 GObjectClass *gobject_class;
117 AdgEntityClass *entity_class;
118 GParamSpec *param;
120 gobject_class = (GObjectClass *) klass;
121 entity_class = (AdgEntityClass *) klass;
123 g_type_class_add_private(klass, sizeof(AdgToyTextPrivate));
125 gobject_class->finalize = finalize;
126 gobject_class->get_property = get_property;
127 gobject_class->set_property = set_property;
129 entity_class->model_matrix_changed = model_matrix_changed;
130 entity_class->invalidate = invalidate;
131 entity_class->render = render;
133 g_object_class_override_property(gobject_class, PROP_ANGLE, "angle");
135 param = g_param_spec_string("label",
136 P_("Label"),
137 P_("The label to display"),
138 NULL, G_PARAM_READWRITE);
139 g_object_class_install_property(gobject_class, PROP_LABEL, param);
142 static void
143 adg_toy_text_init(AdgToyText *toy_text)
145 AdgToyTextPrivate *data = G_TYPE_INSTANCE_GET_PRIVATE(toy_text,
146 ADG_TYPE_TOY_TEXT,
147 AdgToyTextPrivate);
149 data->label = NULL;
150 data->glyphs = NULL;
152 toy_text->data = data;
155 static void
156 finalize(GObject *object)
158 AdgToyText *toy_text;
159 AdgToyTextPrivate *data;
160 GObjectClass *object_class;
162 toy_text = (AdgToyText *) object;
163 data = toy_text->data;
164 object_class = (GObjectClass *) adg_toy_text_parent_class;
166 g_free(data->label);
167 clear_label_cache(toy_text);
169 if (object_class->finalize != NULL)
170 object_class->finalize(object);
173 static void
174 get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
176 AdgToyTextPrivate *data = ((AdgToyText *) object)->data;
178 switch (prop_id) {
179 case PROP_ANGLE:
180 g_value_set_double(value, data->angle);
181 break;
182 case PROP_LABEL:
183 g_value_set_string(value, data->label);
184 break;
185 default:
186 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
187 break;
191 static void
192 set_property(GObject *object, guint prop_id,
193 const GValue *value, GParamSpec *pspec)
195 AdgToyText *toy_text;
196 AdgToyTextPrivate *data;
198 toy_text = (AdgToyText *) object;
199 data = toy_text->data;
201 switch (prop_id) {
202 case PROP_ANGLE:
203 data->angle = g_value_get_double(value);
204 break;
205 case PROP_LABEL:
206 g_free(data->label);
207 data->label = g_value_dup_string(value);
208 clear_label_cache(toy_text);
209 break;
210 default:
211 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
212 break;
218 * adg_toy_text_new:
219 * @label: the label text
221 * Creates a new toy text entity using @label as its text
223 * Return value: the new entity
225 AdgEntity *
226 adg_toy_text_new(const gchar *label)
228 return (AdgEntity *) g_object_new(ADG_TYPE_TOY_TEXT, "label", label, NULL);
232 * adg_toy_text_get_label:
233 * @toy_text: an #AdgToyText
235 * Gets the label text. The string is internally owned and
236 * must not be freed or modified.
238 * Return value: the label text
240 const gchar *
241 adg_toy_text_get_label(AdgToyText *toy_text)
243 AdgToyTextPrivate *data;
245 g_return_val_if_fail(ADG_IS_TOY_TEXT(toy_text), NULL);
247 data = toy_text->data;
249 return data->label;
253 * adg_toy_text_set_label:
254 * @toy_text: an #AdgToyText
255 * @label: the label text
257 * Explicitely sets the text to use as label.
259 void
260 adg_toy_text_set_label(AdgToyText *toy_text, const gchar *label)
262 AdgToyTextPrivate *data;
264 g_return_if_fail(ADG_IS_TOY_TEXT(label));
266 data = toy_text->data;
267 g_free(data->label);
268 data->label = g_strdup(label);
270 g_object_notify((GObject *) toy_text, "label");
271 clear_label_cache(toy_text);
275 static void
276 render(AdgEntity *entity, cairo_t *cr)
278 AdgToyText *toy_text;
279 AdgToyTextPrivate *data;
280 AdgEntityClass *entity_class;
282 toy_text = (AdgToyText *) entity;
283 data = toy_text->data;
284 entity_class = (AdgEntityClass *) adg_toy_text_parent_class;
286 if (data->label) {
287 AdgStyle *font_style;
289 font_style = adg_entity_get_style(entity, ADG_SLOT_FONT_STYLE);
291 cairo_save(cr);
292 cairo_set_matrix(cr, adg_entity_get_paper_matrix(entity));
293 adg_style_apply(font_style, cr);
294 cairo_rotate(cr, data->angle);
296 if (!data->glyphs)
297 update_label_cache(toy_text, cr);
298 update_origin_cache(toy_text, cr);
300 cairo_show_glyphs(cr, data->glyphs, data->num_glyphs);
301 cairo_restore(cr);
304 if (entity_class->render != NULL)
305 entity_class->render(entity, cr);
308 static void
309 model_matrix_changed(AdgEntity *entity, AdgMatrix *parent_matrix)
311 AdgEntityClass *entity_class = (AdgEntityClass *) adg_toy_text_parent_class;
314 if (entity_class->model_matrix_changed != NULL)
315 entity_class->model_matrix_changed(entity, parent_matrix);
318 static void
319 invalidate(AdgEntity *entity)
321 AdgToyText *toy_text;
322 AdgEntityClass *entity_class;
324 toy_text = (AdgToyText *) entity;
325 entity_class = (AdgEntityClass *) adg_toy_text_parent_class;
327 clear_label_cache(toy_text);
329 if (entity_class->invalidate != NULL)
330 entity_class->invalidate(entity);
333 static gboolean
334 update_origin_cache(AdgToyText *toy_text, cairo_t *cr)
336 AdgToyTextPrivate *data;
337 cairo_glyph_t *glyph;
338 int cnt;
339 AdgMatrix matrix;
340 double x, y;
342 data = toy_text->data;
343 glyph = data->glyphs;
344 cnt = data->num_glyphs;
346 /* On undefined label return error */
347 if (glyph == NULL || cnt <= 0)
348 return FALSE;
350 adg_entity_get_local_matrix((AdgEntity *) toy_text, &matrix);
351 cairo_matrix_transform_point(&matrix, &x, &y);
352 adg_entity_get_global_matrix((AdgEntity *) toy_text, &matrix);
353 cairo_matrix_transform_point(&matrix, &x, &y);
355 /* Check if the origin is still the same */
356 if (x == glyph->x && y == glyph->y)
357 return TRUE;
359 x -= glyph->x;
360 y -= glyph->y;
362 while (cnt --) {
363 glyph->x += x;
364 glyph->y += y;
365 ++ glyph;
368 return TRUE;
371 static gboolean
372 update_label_cache(AdgToyText *toy_text, cairo_t *cr)
374 AdgToyTextPrivate *data = toy_text->data;
375 cairo_status_t status;
377 status = cairo_scaled_font_text_to_glyphs(cairo_get_scaled_font(cr),
378 0., 0., data->label, -1,
379 &data->glyphs,
380 &data->num_glyphs,
381 NULL, NULL, NULL);
383 if (status != CAIRO_STATUS_SUCCESS) {
384 g_error("Unable to build glyphs (cairo message: %s)",
385 cairo_status_to_string(status));
386 return FALSE;
389 cairo_glyph_extents(cr, data->glyphs, data->num_glyphs, &data->extents);
391 return TRUE;
394 static void
395 clear_label_cache(AdgToyText *toy_text)
397 AdgToyTextPrivate *data = toy_text->data;
399 if (data->glyphs) {
400 cairo_glyph_free(data->glyphs);
401 data->glyphs = NULL;
404 data->num_glyphs = 0;
405 memset(&data->extents, 0, sizeof(data->extents));