[AdgToyText] Don't set custom properties in _init()
[adg.git] / adg / adg-toy-text.c
blob944913d08f31133bb5cc822ca43736487d1f810c
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-dress-builtins.h"
42 #include "adg-font-style.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_FONT_DRESS,
52 PROP_LABEL
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 global_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_font_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->invalidate = invalidate;
99 entity_class->arrange = arrange;
100 entity_class->render = render;
102 param = adg_param_spec_dress("font-dress",
103 P_("Font Dress"),
104 P_("The font dress to use for rendering this text"),
105 ADG_DRESS_TEXT,
106 G_PARAM_READWRITE);
107 g_object_class_install_property(gobject_class, PROP_FONT_DRESS, param);
109 param = g_param_spec_string("label",
110 P_("Label"),
111 P_("The label to display"),
112 NULL,
113 G_PARAM_READWRITE);
114 g_object_class_install_property(gobject_class, PROP_LABEL, 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->font_dress = ADG_DRESS_TEXT;
125 data->label = NULL;
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 unset_font(toy_text);
142 unset_glyphs(toy_text);
144 if (PARENT_OBJECT_CLASS->finalize != NULL)
145 PARENT_OBJECT_CLASS->finalize(object);
148 static void
149 get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
151 AdgToyTextPrivate *data = ((AdgToyText *) object)->data;
153 switch (prop_id) {
154 case PROP_FONT_DRESS:
155 g_value_set_int(value, data->font_dress);
156 break;
157 case PROP_LABEL:
158 g_value_set_string(value, data->label);
159 break;
160 default:
161 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
162 break;
166 static void
167 set_property(GObject *object, guint prop_id,
168 const GValue *value, GParamSpec *pspec)
170 AdgToyText *toy_text = (AdgToyText *) object;
172 switch (prop_id) {
173 case PROP_FONT_DRESS:
174 set_font_dress(toy_text, g_value_get_int(value));
175 break;
176 case PROP_LABEL:
177 set_label(toy_text, g_value_get_string(value));
178 break;
179 default:
180 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
181 break;
187 * adg_toy_text_new:
188 * @label: the label text
190 * Creates a new toy text entity using @label as its text. The
191 * #AdgEntity:local-mode property is set by default to
192 * #ADG_TRANSFORM_BEFORE_NORMALIZED.
194 * Returns: the newly created toy text entity
196 AdgToyText *
197 adg_toy_text_new(const gchar *label)
199 return g_object_new(ADG_TYPE_TOY_TEXT,
200 "local-mode", ADG_TRANSFORM_BEFORE_NORMALIZED,
201 "label", label, NULL);
205 * adg_toy_text_get_font_dress:
206 * @toy_text: an #AdgToyText
208 * Gets the font dress to be used in rendering @toy_text.
210 * Returns: the current font dress
212 AdgDress
213 adg_toy_text_get_font_dress(AdgToyText *toy_text)
215 AdgToyTextPrivate *data;
217 g_return_val_if_fail(ADG_IS_TOY_TEXT(toy_text), ADG_DRESS_UNDEFINED);
219 data = toy_text->data;
221 return data->font_dress;
225 * adg_toy_text_set_font_dress:
226 * @toy_text: an #AdgToyText
227 * @dress: the new #AdgDress to use
229 * Sets a new font dress for rendering @toy_text. The new dress
230 * must be related to the original dress for this property:
231 * you cannot set a dress used for line styles to a dress
232 * managing fonts.
234 * The check is done by calling adg_dress_are_related() with
235 * @dress and the previous dress as arguments. Check out its
236 * documentation for details on what is a related dress.
238 void
239 adg_toy_text_set_font_dress(AdgToyText *toy_text, AdgDress dress)
241 g_return_if_fail(ADG_IS_TOY_TEXT(toy_text));
243 if (set_font_dress(toy_text, dress))
244 g_object_notify((GObject *) toy_text, "font-dress");
248 * adg_toy_text_get_label:
249 * @toy_text: an #AdgToyText
251 * Gets the label text. The string is internally owned and
252 * must not be freed or modified.
254 * Returns: the label text
256 const gchar *
257 adg_toy_text_get_label(AdgToyText *toy_text)
259 AdgToyTextPrivate *data;
261 g_return_val_if_fail(ADG_IS_TOY_TEXT(toy_text), NULL);
263 data = toy_text->data;
265 return data->label;
269 * adg_toy_text_set_label:
270 * @toy_text: an #AdgToyText
271 * @label: the label text
273 * Sets a new label for @toy_text. @label can be also %NULL,
274 * in which case will be treated as an empty string.
276 void
277 adg_toy_text_set_label(AdgToyText *toy_text, const gchar *label)
279 g_return_if_fail(ADG_IS_TOY_TEXT(toy_text));
281 if (set_label(toy_text, label))
282 g_object_notify((GObject *) toy_text, "label");
286 static void
287 global_changed(AdgEntity *entity)
289 PARENT_ENTITY_CLASS->global_changed(entity);
290 unset_font((AdgToyText *) entity);
293 static void
294 invalidate(AdgEntity *entity)
296 unset_font((AdgToyText *) entity);
297 unset_glyphs((AdgToyText *) entity);
299 if (PARENT_ENTITY_CLASS->invalidate != NULL)
300 return PARENT_ENTITY_CLASS->invalidate(entity);
303 static void
304 arrange(AdgEntity *entity)
306 AdgToyText *toy_text;
307 AdgToyTextPrivate *data;
308 AdgMatrix local;
309 CpmlExtents extents;
311 toy_text = (AdgToyText *) entity;
312 data = toy_text->data;
314 if (data->font == NULL) {
315 AdgFontStyle *font_style = (AdgFontStyle *)
316 adg_entity_style(entity, data->font_dress);
318 data->font = adg_font_style_font(font_style, adg_entity_ctm(entity));
321 if (adg_is_empty(data->label)) {
322 /* Undefined label */
323 extents.is_defined = FALSE;
324 adg_entity_set_extents(entity, &extents);
325 return;
328 if (data->glyphs == NULL) {
329 cairo_status_t status;
330 cairo_text_extents_t cairo_extents;
332 status = cairo_scaled_font_text_to_glyphs(data->font, 0, 0,
333 data->label, -1,
334 &data->glyphs,
335 &data->num_glyphs,
336 NULL, NULL, NULL);
338 if (status != CAIRO_STATUS_SUCCESS) {
339 unset_glyphs(toy_text);
340 g_error("Unable to build glyphs (cairo message: %s)",
341 cairo_status_to_string(status));
342 return;
345 cairo_scaled_font_glyph_extents(data->font, data->glyphs,
346 data->num_glyphs, &cairo_extents);
347 cpml_extents_from_cairo_text(&extents, &cairo_extents);
348 adg_entity_get_local_map(entity, &local);
349 cairo_matrix_transform_point(&local, &extents.org.x, &extents.org.y);
350 cairo_matrix_transform_distance(&local, &extents.size.x, &extents.size.y);
352 adg_entity_set_extents(entity, &extents);
356 static void
357 render(AdgEntity *entity, cairo_t *cr)
359 AdgToyText *toy_text;
360 AdgToyTextPrivate *data;
362 toy_text = (AdgToyText *) entity;
363 data = toy_text->data;
365 if (data->glyphs != NULL) {
366 adg_entity_apply_dress(entity, data->font_dress, cr);
367 cairo_set_matrix(cr, adg_entity_ctm(entity));
368 cairo_show_glyphs(cr, data->glyphs, data->num_glyphs);
372 static gboolean
373 set_font_dress(AdgToyText *toy_text, AdgDress dress)
375 AdgToyTextPrivate *data = toy_text->data;
377 if (adg_dress_set(&data->font_dress, dress)) {
378 unset_font(toy_text);
379 return TRUE;
382 return FALSE;
385 static gboolean
386 set_label(AdgToyText *toy_text, const gchar *label)
388 AdgToyTextPrivate *data = toy_text->data;
390 /* Check if the new label differs from the current label */
391 if (adg_strcmp(label, data->label) == 0)
392 return FALSE;
394 g_free(data->label);
395 data->label = g_strdup(label);
397 unset_glyphs(toy_text);
398 return TRUE;
401 static void
402 unset_font(AdgToyText *toy_text)
404 AdgToyTextPrivate *data = toy_text->data;
406 data->font = NULL;
409 static void
410 unset_glyphs(AdgToyText *toy_text)
412 AdgToyTextPrivate *data = toy_text->data;
414 if (data->glyphs != NULL) {
415 cairo_glyph_free(data->glyphs);
416 data->glyphs = NULL;
419 data->num_glyphs = 0;