[AdgToyText] Forcibly unset the font in global-changed
[adg.git] / adg / adg-toy-text.c
blobff109000246c27ca03f6a8a8d3d82634e3071a15
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-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 global_changed (AdgEntity *entity);
65 static void local_changed (AdgEntity *entity);
66 static void invalidate (AdgEntity *entity);
67 static void arrange (AdgEntity *entity);
68 static void render (AdgEntity *entity,
69 cairo_t *cr);
70 static gboolean set_dress (AdgToyText *toy_text,
71 AdgDress dress);
72 static gboolean set_label (AdgToyText *toy_text,
73 const gchar *label);
74 static void unset_font (AdgToyText *toy_text);
75 static void unset_glyphs (AdgToyText *toy_text);
78 G_DEFINE_TYPE(AdgToyText, adg_toy_text, ADG_TYPE_ENTITY);
81 static void
82 adg_toy_text_class_init(AdgToyTextClass *klass)
84 GObjectClass *gobject_class;
85 AdgEntityClass *entity_class;
86 GParamSpec *param;
88 gobject_class = (GObjectClass *) klass;
89 entity_class = (AdgEntityClass *) klass;
91 g_type_class_add_private(klass, sizeof(AdgToyTextPrivate));
93 gobject_class->finalize = finalize;
94 gobject_class->get_property = get_property;
95 gobject_class->set_property = set_property;
97 entity_class->global_changed = global_changed;
98 entity_class->local_changed = local_changed;
99 entity_class->invalidate = invalidate;
100 entity_class->arrange = arrange;
101 entity_class->render = render;
103 param = adg_param_spec_dress("dress",
104 P_("Font Dress"),
105 P_("The font dress to use for rendering this text"),
106 ADG_DRESS_TEXT_REGULAR,
107 G_PARAM_READWRITE);
108 g_object_class_install_property(gobject_class, PROP_DRESS, param);
110 param = g_param_spec_string("label",
111 P_("Label"),
112 P_("The label to display"),
113 NULL,
114 G_PARAM_READWRITE);
115 g_object_class_install_property(gobject_class, PROP_LABEL, param);
118 static void
119 adg_toy_text_init(AdgToyText *toy_text)
121 AdgToyTextPrivate *data = G_TYPE_INSTANCE_GET_PRIVATE(toy_text,
122 ADG_TYPE_TOY_TEXT,
123 AdgToyTextPrivate);
125 data->dress = ADG_DRESS_TEXT_REGULAR;
126 data->label = NULL;
127 data->glyphs = NULL;
129 toy_text->data = data;
132 static void
133 finalize(GObject *object)
135 AdgToyText *toy_text;
136 AdgToyTextPrivate *data;
138 toy_text = (AdgToyText *) object;
139 data = toy_text->data;
141 g_free(data->label);
142 unset_font(toy_text);
143 unset_glyphs(toy_text);
145 if (PARENT_OBJECT_CLASS->finalize != NULL)
146 PARENT_OBJECT_CLASS->finalize(object);
149 static void
150 get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
152 AdgToyTextPrivate *data = ((AdgToyText *) object)->data;
154 switch (prop_id) {
155 case PROP_DRESS:
156 g_value_set_int(value, data->dress);
157 break;
158 case PROP_LABEL:
159 g_value_set_string(value, data->label);
160 break;
161 default:
162 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
163 break;
167 static void
168 set_property(GObject *object, guint prop_id,
169 const GValue *value, GParamSpec *pspec)
171 AdgToyText *toy_text = (AdgToyText *) object;
173 switch (prop_id) {
174 case PROP_DRESS:
175 set_dress(toy_text, g_value_get_int(value));
176 break;
177 case PROP_LABEL:
178 set_label(toy_text, g_value_get_string(value));
179 break;
180 default:
181 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
182 break;
188 * adg_toy_text_new:
189 * @label: the label text
191 * Creates a new toy text entity using @label as its text
193 * Returns: the newly created toy text entity
195 AdgToyText *
196 adg_toy_text_new(const gchar *label)
198 return g_object_new(ADG_TYPE_TOY_TEXT, "label", label, NULL);
202 * adg_toy_text_get_dress:
203 * @toy_text: an #AdgToyText
205 * Gets the font dress to be used in rendering @toy_text.
207 * Returns: the current font dress
209 AdgDress
210 adg_toy_text_get_dress(AdgToyText *toy_text)
212 AdgToyTextPrivate *data;
214 g_return_val_if_fail(ADG_IS_TOY_TEXT(toy_text), ADG_DRESS_UNDEFINED);
216 data = toy_text->data;
218 return data->dress;
222 * adg_toy_text_set_dress:
223 * @toy_text: an #AdgToyText
224 * @dress: the new #AdgDress to use
226 * Sets a new font dress for rendering @toy_text. The new dress
227 * must be related to the original dress for this property:
228 * you cannot set a dress used for line styles to a dress
229 * managing fonts.
231 * The check is done by calling adg_dress_are_related() with
232 * @dress and the previous dress as arguments. Check out its
233 * documentation for details on what is a related dress.
235 void
236 adg_toy_text_set_dress(AdgToyText *toy_text, AdgDress dress)
238 g_return_if_fail(ADG_IS_TOY_TEXT(toy_text));
240 if (set_dress(toy_text, dress))
241 g_object_notify((GObject *) toy_text, "dress");
245 * adg_toy_text_get_label:
246 * @toy_text: an #AdgToyText
248 * Gets the label text. The string is internally owned and
249 * must not be freed or modified.
251 * Returns: the label text
253 const gchar *
254 adg_toy_text_get_label(AdgToyText *toy_text)
256 AdgToyTextPrivate *data;
258 g_return_val_if_fail(ADG_IS_TOY_TEXT(toy_text), NULL);
260 data = toy_text->data;
262 return data->label;
266 * adg_toy_text_set_label:
267 * @toy_text: an #AdgToyText
268 * @label: the label text
270 * Sets a new label for @toy_text. @label can be also %NULL,
271 * in which case will be treated as an empty string.
273 void
274 adg_toy_text_set_label(AdgToyText *toy_text, const gchar *label)
276 g_return_if_fail(ADG_IS_TOY_TEXT(toy_text));
278 if (set_label(toy_text, label))
279 g_object_notify((GObject *) toy_text, "label");
283 static void
284 global_changed(AdgEntity *entity)
286 unset_font((AdgToyText *) entity);
288 PARENT_ENTITY_CLASS->global_changed(entity);
291 static void
292 local_changed(AdgEntity *entity)
294 AdgMatrix old, new;
295 CpmlExtents extents;
297 adg_entity_get_local_matrix(entity, &old);
299 PARENT_ENTITY_CLASS->local_changed(entity);
301 adg_entity_get_local_matrix(entity, &new);
302 cairo_matrix_init_translate(&new, new.x0, new.y0);
303 adg_entity_set_local_matrix(entity, &new);
305 /* Update the extents position (if needed) without
306 * invalidating the font */
307 adg_entity_get_extents(entity, &extents);
309 if (extents.is_defined) {
310 extents.org.x += new.x0 - old.x0;
311 extents.org.y += new.y0 - old.y0;
312 adg_entity_set_extents(entity, &extents);
316 static void
317 invalidate(AdgEntity *entity)
319 unset_font((AdgToyText *) entity);
320 unset_glyphs((AdgToyText *) entity);
322 if (PARENT_ENTITY_CLASS->invalidate != NULL)
323 return PARENT_ENTITY_CLASS->invalidate(entity);
326 static void
327 arrange(AdgEntity *entity)
329 AdgToyText *toy_text;
330 AdgToyTextPrivate *data;
331 cairo_status_t status;
332 cairo_text_extents_t cairo_extents;
333 AdgMatrix local;
334 CpmlExtents extents;
336 toy_text = (AdgToyText *) entity;
337 data = toy_text->data;
339 if (data->font == NULL) {
340 AdgFontStyle *font_style;
341 AdgMatrix ctm;
343 font_style = (AdgFontStyle *) adg_entity_style(entity, data->dress);
344 adg_entity_get_global_matrix(entity, &ctm);
345 data->font = adg_font_style_font(font_style, &ctm);
348 if (data->glyphs != NULL || data->label == NULL || data->label[0] == '\0')
349 return;
351 status = cairo_scaled_font_text_to_glyphs(data->font, 0, 0,
352 data->label, -1,
353 &data->glyphs,
354 &data->num_glyphs,
355 NULL, NULL, NULL);
357 if (status != CAIRO_STATUS_SUCCESS) {
358 unset_glyphs(toy_text);
359 g_error("Unable to build glyphs (cairo message: %s)",
360 cairo_status_to_string(status));
361 return;
364 cairo_scaled_font_glyph_extents(data->font, data->glyphs,
365 data->num_glyphs, &cairo_extents);
366 cpml_extents_from_cairo_text(&extents, &cairo_extents);
368 adg_entity_get_local_map(entity, &local);
369 cairo_matrix_transform_point(&local, &extents.org.x, &extents.org.y);
370 cairo_matrix_transform_distance(&local, &extents.size.x, &extents.size.y);
372 adg_entity_set_extents(entity, &extents);
375 static void
376 render(AdgEntity *entity, cairo_t *cr)
378 AdgToyText *toy_text;
379 AdgToyTextPrivate *data;
381 toy_text = (AdgToyText *) entity;
382 data = toy_text->data;
384 if (data->glyphs != NULL) {
385 cairo_save(cr);
386 cairo_set_scaled_font(cr, data->font);
387 adg_entity_apply_local_matrix(entity, cr);
388 cairo_show_glyphs(cr, data->glyphs, data->num_glyphs);
389 cairo_restore(cr);
393 static gboolean
394 set_dress(AdgToyText *toy_text, AdgDress dress)
396 AdgToyTextPrivate *data = toy_text->data;
398 if (adg_dress_set(&data->dress, dress)) {
399 unset_font(toy_text);
400 return TRUE;
403 return FALSE;
406 static gboolean
407 set_label(AdgToyText *toy_text, const gchar *label)
409 AdgToyTextPrivate *data = toy_text->data;
411 /* Check if the new label differs from the current label */
412 if (adg_strcmp(label, data->label) == 0)
413 return FALSE;
415 g_free(data->label);
416 data->label = g_strdup(label);
418 unset_glyphs(toy_text);
419 return TRUE;
422 static void
423 unset_font(AdgToyText *toy_text)
425 AdgToyTextPrivate *data = toy_text->data;
427 data->font = NULL;
430 static void
431 unset_glyphs(AdgToyText *toy_text)
433 AdgToyTextPrivate *data = toy_text->data;
435 if (data->glyphs != NULL) {
436 cairo_glyph_free(data->glyphs);
437 data->glyphs = NULL;
440 data->num_glyphs = 0;