doc: update copyright line for 2021
[adg.git] / src / adg / adg-toy-text.c
blobb70ceee11c2b1a7fe3203949337a5b027e449c0a
1 /* ADG - Automatic Drawing Generation
2 * Copyright (C) 2007-2021 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 uses 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.
30 * <note><para>
31 * By default, the #AdgEntity:local-mix property is set to
32 * #ADG_MIX_ANCESTORS_NORMALIZED on #AdgToyText entities.
33 * </para></note>
35 * Since: 1.0
36 **/
38 /**
39 * AdgToyText:
41 * All fields are privates and should not be used directly.
42 * Use its public methods instead.
44 * Since: 1.0
45 **/
48 #include "adg-internal.h"
49 #include "adg-dress.h"
50 #include "adg-style.h"
51 #include "adg-font-style.h"
52 #include "adg-textual.h"
54 #include "adg-toy-text.h"
55 #include "adg-toy-text-private.h"
58 #define _ADG_OLD_OBJECT_CLASS ((GObjectClass *) adg_toy_text_parent_class)
59 #define _ADG_OLD_ENTITY_CLASS ((AdgEntityClass *) adg_toy_text_parent_class)
62 static void _adg_iface_init (AdgTextualIface *iface);
65 G_DEFINE_TYPE_WITH_CODE(AdgToyText, adg_toy_text, ADG_TYPE_ENTITY,
66 G_IMPLEMENT_INTERFACE(ADG_TYPE_TEXTUAL, _adg_iface_init)
67 G_ADD_PRIVATE(AdgToyText))
69 enum {
70 PROP_0,
71 PROP_FONT_DRESS,
72 PROP_TEXT
76 static void _adg_finalize (GObject *object);
77 static void _adg_get_property (GObject *object,
78 guint param_id,
79 GValue *value,
80 GParamSpec *pspec);
81 static void _adg_set_property (GObject *object,
82 guint param_id,
83 const GValue *value,
84 GParamSpec *pspec);
85 static void _adg_global_changed (AdgEntity *entity);
86 static void _adg_local_changed (AdgEntity *entity);
87 static void _adg_invalidate (AdgEntity *entity);
88 static void _adg_arrange (AdgEntity *entity);
89 static void _adg_render (AdgEntity *entity,
90 cairo_t *cr);
91 static void _adg_set_font_dress (AdgTextual *textual,
92 AdgDress dress);
93 static AdgDress _adg_get_font_dress (AdgTextual *textual);
94 static void _adg_set_text (AdgTextual *textual,
95 const gchar *text);
96 static gchar * _adg_dup_text (AdgTextual *textual);
97 static void _adg_clear_font (AdgToyText *toy_text);
98 static void _adg_clear_glyphs (AdgToyText *toy_text);
101 static void
102 adg_toy_text_class_init(AdgToyTextClass *klass)
104 GObjectClass *gobject_class;
105 AdgEntityClass *entity_class;
107 gobject_class = (GObjectClass *) klass;
108 entity_class = (AdgEntityClass *) klass;
110 gobject_class->finalize = _adg_finalize;
111 gobject_class->get_property = _adg_get_property;
112 gobject_class->set_property = _adg_set_property;
114 entity_class->global_changed = _adg_global_changed;
115 entity_class->local_changed = _adg_local_changed;
116 entity_class->invalidate = _adg_invalidate;
117 entity_class->arrange = _adg_arrange;
118 entity_class->render = _adg_render;
120 g_object_class_override_property(gobject_class, PROP_FONT_DRESS, "font-dress");
121 g_object_class_override_property(gobject_class, PROP_TEXT, "text");
124 static void
125 _adg_iface_init(AdgTextualIface *iface)
127 iface->set_font_dress = _adg_set_font_dress;
128 iface->get_font_dress = _adg_get_font_dress;
129 iface->set_text = _adg_set_text;
130 iface->dup_text = _adg_dup_text;
131 iface->text_changed = NULL;
134 static void
135 adg_toy_text_init(AdgToyText *toy_text)
137 AdgToyTextPrivate *data = adg_toy_text_get_instance_private(toy_text);
138 data->font_dress = ADG_DRESS_FONT_TEXT;
139 data->text = NULL;
140 data->glyphs = NULL;
141 adg_entity_set_local_mix((AdgEntity *) toy_text, ADG_MIX_ANCESTORS_NORMALIZED);
144 static void
145 _adg_finalize(GObject *object)
147 AdgToyText *toy_text = (AdgToyText *) object;
148 AdgToyTextPrivate *data = adg_toy_text_get_instance_private(toy_text);
150 g_free(data->text);
151 _adg_clear_font(toy_text);
152 _adg_clear_glyphs(toy_text);
154 if (_ADG_OLD_OBJECT_CLASS->finalize)
155 _ADG_OLD_OBJECT_CLASS->finalize(object);
158 static void
159 _adg_get_property(GObject *object, guint prop_id,
160 GValue *value, GParamSpec *pspec)
162 AdgToyTextPrivate *data = adg_toy_text_get_instance_private((AdgToyText *) object);
164 switch (prop_id) {
165 case PROP_FONT_DRESS:
166 g_value_set_enum(value, data->font_dress);
167 break;
168 case PROP_TEXT:
169 g_value_set_string(value, data->text);
170 break;
171 default:
172 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
173 break;
177 static void
178 _adg_set_property(GObject *object, guint prop_id,
179 const GValue *value, GParamSpec *pspec)
181 AdgToyText *toy_text = (AdgToyText *) object;
182 AdgToyTextPrivate *data = adg_toy_text_get_instance_private(toy_text);
184 switch (prop_id) {
185 case PROP_FONT_DRESS:
186 data->font_dress = g_value_get_enum(value);
187 _adg_clear_font(toy_text);
188 break;
189 case PROP_TEXT:
190 g_free(data->text);
191 data->text = g_value_dup_string(value);
192 _adg_clear_glyphs(toy_text);
193 break;
194 default:
195 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
196 break;
202 * adg_toy_text_new:
203 * @text: the text
205 * Creates a new toy text entity using @text as its content.
207 * Returns: the newly created toy text entity
209 * Since: 1.0
211 AdgToyText *
212 adg_toy_text_new(const gchar *text)
214 return g_object_new(ADG_TYPE_TOY_TEXT,
215 "text", text, NULL);
219 static void
220 _adg_global_changed(AdgEntity *entity)
222 if (_ADG_OLD_ENTITY_CLASS->global_changed)
223 _ADG_OLD_ENTITY_CLASS->global_changed(entity);
225 adg_entity_invalidate(entity);
228 static void
229 _adg_local_changed(AdgEntity *entity)
231 if (_ADG_OLD_ENTITY_CLASS->local_changed)
232 _ADG_OLD_ENTITY_CLASS->local_changed(entity);
234 adg_entity_invalidate(entity);
237 static void
238 _adg_invalidate(AdgEntity *entity)
240 _adg_clear_font((AdgToyText *) entity);
241 _adg_clear_glyphs((AdgToyText *) entity);
243 if (_ADG_OLD_ENTITY_CLASS->invalidate)
244 _ADG_OLD_ENTITY_CLASS->invalidate(entity);
247 static void
248 _adg_arrange(AdgEntity *entity)
250 AdgToyText *toy_text = (AdgToyText *) entity;
251 AdgToyTextPrivate *data = adg_toy_text_get_instance_private(toy_text);
252 CpmlExtents extents;
254 if (data->font == NULL) {
255 AdgDress dress;
256 AdgFontStyle *font_style;
257 cairo_matrix_t ctm;
259 dress = data->font_dress;
260 font_style = (AdgFontStyle *) adg_entity_style(entity, dress);
262 adg_matrix_copy(&ctm, adg_entity_get_global_matrix(entity));
263 adg_matrix_transform(&ctm, adg_entity_get_local_matrix(entity),
264 ADG_TRANSFORM_BEFORE);
266 data->font = adg_font_style_get_scaled_font(font_style, &ctm);
269 if (adg_is_string_empty(data->text)) {
270 /* Undefined text */
271 extents.is_defined = FALSE;
272 } else if (data->glyphs != NULL) {
273 /* Cached result */
274 return;
275 } else {
276 cairo_status_t status;
277 cairo_text_extents_t cairo_extents;
279 status = cairo_scaled_font_text_to_glyphs(data->font, 0, 0,
280 data->text, -1,
281 &data->glyphs,
282 &data->num_glyphs,
283 NULL, NULL, NULL);
285 if (status != CAIRO_STATUS_SUCCESS) {
286 _adg_clear_glyphs(toy_text);
287 g_error(_("Unable to build glyphs (cairo message: %s)"),
288 cairo_status_to_string(status));
289 return;
292 cairo_scaled_font_glyph_extents(data->font, data->glyphs,
293 data->num_glyphs, &cairo_extents);
294 cpml_extents_from_cairo_text(&extents, &cairo_extents);
295 cpml_extents_transform(&extents, adg_entity_get_local_matrix(entity));
296 cpml_extents_transform(&extents, adg_entity_get_global_matrix(entity));
300 adg_entity_set_extents(entity, &extents);
303 static void
304 _adg_render(AdgEntity *entity, cairo_t *cr)
306 AdgToyText *toy_text = (AdgToyText *) entity;
307 AdgToyTextPrivate *data = adg_toy_text_get_instance_private(toy_text);
309 if (data->glyphs != NULL) {
310 adg_entity_apply_dress(entity, data->font_dress, cr);
311 cairo_transform(cr, adg_entity_get_global_matrix(entity));
312 cairo_transform(cr, adg_entity_get_local_matrix(entity));
313 cairo_show_glyphs(cr, data->glyphs, data->num_glyphs);
317 static void
318 _adg_set_font_dress(AdgTextual *textual, AdgDress dress)
320 g_object_set(textual, "font-dress", dress, NULL);
323 static AdgDress
324 _adg_get_font_dress(AdgTextual *textual)
326 AdgToyTextPrivate *data = adg_toy_text_get_instance_private((AdgToyText *) textual);
327 return data->font_dress;
330 static void
331 _adg_set_text(AdgTextual *textual, const gchar *text)
333 g_object_set(textual, "text", text, NULL);
336 static gchar *
337 _adg_dup_text(AdgTextual *textual)
339 AdgToyTextPrivate *data = adg_toy_text_get_instance_private((AdgToyText *) textual);
340 return g_strdup(data->text);
343 static void
344 _adg_clear_font(AdgToyText *toy_text)
346 AdgToyTextPrivate *data = adg_toy_text_get_instance_private(toy_text);
347 data->font = NULL;
350 static void
351 _adg_clear_glyphs(AdgToyText *toy_text)
353 AdgToyTextPrivate *data = adg_toy_text_get_instance_private(toy_text);
355 if (data->glyphs != NULL) {
356 cairo_glyph_free(data->glyphs);
357 data->glyphs = NULL;
360 data->num_glyphs = 0;