[docs] Removed useless tracked files from adg
[adg.git] / adg / adg-toy-text.c
blobee8fcbf382d8e89d399550b0716fb1f422eec6fd
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: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-translatable.h"
41 #include "adg-rotable.h"
42 #include "adg-font-style.h"
43 #include "adg-intl.h"
46 enum {
47 PROP_0,
48 PROP_ORIGIN,
49 PROP_ANGLE,
50 PROP_LABEL
53 static void translatable_init (AdgTranslatableIface *iface);
54 static void get_origin (AdgTranslatable*translatable,
55 AdgPoint *dest);
56 static void set_origin (AdgTranslatable*translatable,
57 const AdgPoint *origin);
59 static void rotable_init (AdgRotableIface*iface);
60 static gdouble get_angle (AdgRotable *rotable);
61 static void set_angle (AdgRotable *rotable,
62 gdouble angle);
64 static void finalize (GObject *object);
65 static void get_property (GObject *object,
66 guint param_id,
67 GValue *value,
68 GParamSpec *pspec);
69 static void set_property (GObject *object,
70 guint param_id,
71 const GValue *value,
72 GParamSpec *pspec);
73 static void model_matrix_changed (AdgEntity *entity,
74 AdgMatrix *parent_matrix);
75 static void invalidate (AdgEntity *entity);
76 static void render (AdgEntity *entity,
77 cairo_t *cr);
78 static gboolean update_origin_cache (AdgToyText *toy_text,
79 cairo_t *cr);
80 static gboolean update_label_cache (AdgToyText *toy_text,
81 cairo_t *cr);
82 static void clear_label_cache (AdgToyText *toy_text);
83 static void clear_origin_cache (AdgToyText *toy_text);
86 G_DEFINE_TYPE_WITH_CODE(AdgToyText, adg_toy_text, ADG_TYPE_ENTITY,
87 G_IMPLEMENT_INTERFACE(ADG_TYPE_TRANSLATABLE,
88 translatable_init)
89 G_IMPLEMENT_INTERFACE(ADG_TYPE_ROTABLE, rotable_init))
92 static void
93 translatable_init(AdgTranslatableIface *iface)
95 iface->get_origin = get_origin;
96 iface->set_origin = set_origin;
99 static void
100 get_origin(AdgTranslatable *translatable, AdgPoint *dest)
102 AdgToyText *toy_text;
103 AdgToyTextPrivate *data;
105 toy_text = (AdgToyText *) translatable;
106 data = toy_text->data;
108 adg_point_copy(dest, &data->origin);
111 static void
112 set_origin(AdgTranslatable *translatable, const AdgPoint *origin)
114 AdgToyText *toy_text;
115 AdgToyTextPrivate *data;
117 toy_text = (AdgToyText *) translatable;
118 data = toy_text->data;
120 adg_point_copy(&data->origin, origin);
124 static void
125 rotable_init(AdgRotableIface *iface)
127 iface->get_angle = get_angle;
128 iface->set_angle = set_angle;
131 static gdouble
132 get_angle(AdgRotable *rotable)
134 AdgToyText *toy_text;
135 AdgToyTextPrivate *data;
137 toy_text = (AdgToyText *) rotable;
138 data = toy_text->data;
140 return data->angle;
143 static void
144 set_angle(AdgRotable *rotable, gdouble angle)
146 AdgToyText *toy_text;
147 AdgToyTextPrivate *data;
149 toy_text = (AdgToyText *) rotable;
150 data = toy_text->data;
152 data->angle = angle;
156 static void
157 adg_toy_text_class_init(AdgToyTextClass *klass)
159 GObjectClass *gobject_class;
160 AdgEntityClass *entity_class;
161 GParamSpec *param;
163 gobject_class = (GObjectClass *) klass;
164 entity_class = (AdgEntityClass *) klass;
166 g_type_class_add_private(klass, sizeof(AdgToyTextPrivate));
168 gobject_class->finalize = finalize;
169 gobject_class->get_property = get_property;
170 gobject_class->set_property = set_property;
172 entity_class->model_matrix_changed = model_matrix_changed;
173 entity_class->invalidate = invalidate;
174 entity_class->render = render;
176 g_object_class_override_property(gobject_class, PROP_ORIGIN, "origin");
177 g_object_class_override_property(gobject_class, PROP_ANGLE, "angle");
179 param = g_param_spec_string("label",
180 P_("Label"),
181 P_("The label to display"),
182 NULL, G_PARAM_READWRITE);
183 g_object_class_install_property(gobject_class, PROP_LABEL, param);
186 static void
187 adg_toy_text_init(AdgToyText *toy_text)
189 AdgToyTextPrivate *data = G_TYPE_INSTANCE_GET_PRIVATE(toy_text,
190 ADG_TYPE_TOY_TEXT,
191 AdgToyTextPrivate);
193 data->label = NULL;
194 adg_point_unset(&data->origin);
196 data->origin_cached = FALSE;
197 data->glyphs = NULL;
199 toy_text->data = data;
202 static void
203 finalize(GObject *object)
205 AdgToyText *toy_text;
206 AdgToyTextPrivate *data;
207 GObjectClass *object_class;
209 toy_text = (AdgToyText *) object;
210 data = toy_text->data;
211 object_class = (GObjectClass *) adg_toy_text_parent_class;
213 g_free(data->label);
214 clear_label_cache(toy_text);
215 clear_origin_cache(toy_text);
217 if (object_class->finalize != NULL)
218 object_class->finalize(object);
221 static void
222 get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
224 AdgToyTextPrivate *data = ((AdgToyText *) object)->data;
226 switch (prop_id) {
227 case PROP_ORIGIN:
228 g_value_set_boxed(value, &data->origin);
229 break;
230 case PROP_ANGLE:
231 g_value_set_double(value, data->angle);
232 break;
233 case PROP_LABEL:
234 g_value_set_string(value, data->label);
235 break;
236 default:
237 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
238 break;
242 static void
243 set_property(GObject *object, guint prop_id,
244 const GValue *value, GParamSpec *pspec)
246 AdgToyText *toy_text;
247 AdgToyTextPrivate *data;
249 toy_text = (AdgToyText *) object;
250 data = toy_text->data;
252 switch (prop_id) {
253 case PROP_ORIGIN:
254 adg_point_copy(&data->origin, (AdgPoint *) g_value_get_boxed(value));
255 clear_origin_cache(toy_text);
256 break;
257 case PROP_ANGLE:
258 data->angle = g_value_get_double(value);
259 clear_origin_cache(toy_text);
260 break;
261 case PROP_LABEL:
262 g_free(data->label);
263 data->label = g_value_dup_string(value);
264 clear_label_cache(toy_text);
265 break;
266 default:
267 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
268 break;
274 * adg_toy_text_new:
275 * @label: the label text
277 * Creates a new toy text entity using @label as its text
279 * Return value: the new entity
281 AdgEntity *
282 adg_toy_text_new(const gchar *label)
284 return (AdgEntity *) g_object_new(ADG_TYPE_TOY_TEXT, "label", label, NULL);
288 * adg_toy_text_get_label:
289 * @toy_text: an #AdgToyText
291 * Gets the label text. The string is internally owned and
292 * must not be freed or modified.
294 * Return value: the label text
296 const gchar *
297 adg_toy_text_get_label(AdgToyText *toy_text)
299 AdgToyTextPrivate *data;
301 g_return_val_if_fail(ADG_IS_TOY_TEXT(toy_text), NULL);
303 data = toy_text->data;
305 return data->label;
309 * adg_toy_text_set_label:
310 * @toy_text: an #AdgToyText
311 * @label: the label text
313 * Explicitely sets the text to use as label.
315 void
316 adg_toy_text_set_label(AdgToyText *toy_text, const gchar *label)
318 AdgToyTextPrivate *data;
320 g_return_if_fail(ADG_IS_TOY_TEXT(label));
322 data = toy_text->data;
323 g_free(data->label);
324 data->label = g_strdup(label);
326 g_object_notify((GObject *) toy_text, "label");
327 clear_label_cache(toy_text);
331 static void
332 render(AdgEntity *entity, cairo_t *cr)
334 AdgToyText *toy_text;
335 AdgToyTextPrivate *data;
336 AdgEntityClass *entity_class;
338 toy_text = (AdgToyText *) entity;
339 data = toy_text->data;
340 entity_class = (AdgEntityClass *) adg_toy_text_parent_class;
342 if (data->label) {
343 AdgStyle *font_style;
345 font_style = adg_entity_get_style(entity, ADG_SLOT_FONT_STYLE);
347 cairo_save(cr);
348 cairo_set_matrix(cr, adg_entity_get_paper_matrix(entity));
349 adg_style_apply(font_style, cr);
350 cairo_rotate(cr, data->angle);
352 if (!data->glyphs)
353 update_label_cache(toy_text, cr);
354 if (!data->origin_cached)
355 update_origin_cache(toy_text, cr);
357 cairo_show_glyphs(cr, data->glyphs, data->num_glyphs);
358 cairo_restore(cr);
361 if (entity_class->render != NULL)
362 entity_class->render(entity, cr);
365 static void
366 model_matrix_changed(AdgEntity *entity, AdgMatrix *parent_matrix)
368 AdgEntityClass *entity_class = (AdgEntityClass *) adg_toy_text_parent_class;
370 clear_origin_cache((AdgToyText *) entity);
372 if (entity_class->model_matrix_changed != NULL)
373 entity_class->model_matrix_changed(entity, parent_matrix);
376 static void
377 invalidate(AdgEntity *entity)
379 AdgToyText *toy_text;
380 AdgEntityClass *entity_class;
382 toy_text = (AdgToyText *) entity;
383 entity_class = (AdgEntityClass *) adg_toy_text_parent_class;
385 clear_label_cache(toy_text);
386 clear_origin_cache(toy_text);
388 if (entity_class->invalidate != NULL)
389 entity_class->invalidate(entity);
392 static gboolean
393 update_origin_cache(AdgToyText *toy_text, cairo_t *cr)
395 AdgToyTextPrivate *data;
396 AdgPoint point;
397 AdgPair *pair;
398 cairo_glyph_t *glyph;
399 double x, y;
400 int cnt;
402 data = toy_text->data;
403 adg_point_copy(&point, &data->origin);
404 pair = &data->origin_pair;
405 glyph = data->glyphs;
406 cnt = data->num_glyphs;
408 /* On undefined label return error */
409 if (glyph == NULL || cnt <= 0)
410 return FALSE;
412 if (data->angle != 0.) {
413 /* Following the less surprise rule, also the paper component
414 * of the origin point should rotate with the provided angle */
415 cairo_matrix_t rotation;
416 cairo_matrix_init_rotate(&rotation, data->angle);
417 cpml_pair_transform(&point.paper, &rotation);
420 adg_entity_point_to_pair((AdgEntity *) toy_text, &point, pair, cr);
421 data->origin_cached = TRUE;
423 /* Check if the origin is still the same */
424 if (pair->x == glyph->x && pair->y == glyph->y)
425 return TRUE;
427 x = pair->x - glyph->x;
428 y = pair->y - glyph->y;
430 while (cnt --) {
431 glyph->x += x;
432 glyph->y += y;
433 ++ glyph;
436 return TRUE;
439 static gboolean
440 update_label_cache(AdgToyText *toy_text, cairo_t *cr)
442 AdgToyTextPrivate *data = toy_text->data;
443 cairo_status_t status;
445 status = cairo_scaled_font_text_to_glyphs(cairo_get_scaled_font(cr),
446 0., 0., data->label, -1,
447 &data->glyphs,
448 &data->num_glyphs,
449 NULL, NULL, NULL);
451 if (status != CAIRO_STATUS_SUCCESS) {
452 g_error("Unable to build glyphs (cairo message: %s)",
453 cairo_status_to_string(status));
454 return FALSE;
457 cairo_glyph_extents(cr, data->glyphs, data->num_glyphs, &data->extents);
459 clear_origin_cache(toy_text);
460 return TRUE;
463 static void
464 clear_origin_cache(AdgToyText *toy_text)
466 AdgToyTextPrivate *data = toy_text->data;
468 data->origin_cached = FALSE;
471 static void
472 clear_label_cache(AdgToyText *toy_text)
474 AdgToyTextPrivate *data = toy_text->data;
476 if (data->glyphs) {
477 cairo_glyph_free(data->glyphs);
478 data->glyphs = NULL;
481 data->num_glyphs = 0;
482 memset(&data->extents, 0, sizeof(data->extents));