1 /* ADG - Automatic Drawing Generation
2 * Copyright (C) 2007-2008, 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.
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.
29 #include "adg-toy-text.h"
30 #include "adg-toy-text-private.h"
31 #include "adg-positionable.h"
32 #include "adg-font-style.h"
35 #define PARENT_CLASS ((AdgEntityClass *) adg_toy_text_parent_class)
44 static void positionable_init (AdgPositionableIface
*iface
);
45 static AdgPoint
*org (AdgPositionable
*positionable
);
47 static void finalize (GObject
*object
);
48 static void get_property (GObject
*object
,
52 static void set_property (GObject
*object
,
56 static void model_matrix_changed (AdgEntity
*entity
,
57 AdgMatrix
*parent_matrix
);
58 static void invalidate (AdgEntity
*entity
);
59 static void render (AdgEntity
*entity
,
61 static gboolean
update_org_cache (AdgToyText
*toy_text
);
62 static gboolean
update_label_cache (AdgToyText
*toy_text
,
64 static void clear_label_cache (AdgToyText
*toy_text
);
65 static void move_label_cache (AdgToyText
*toy_text
,
69 G_DEFINE_TYPE_WITH_CODE(AdgToyText
, adg_toy_text
, ADG_TYPE_ENTITY
,
70 G_IMPLEMENT_INTERFACE(ADG_TYPE_POSITIONABLE
,
75 adg_toy_text_class_init(AdgToyTextClass
*klass
)
77 GObjectClass
*gobject_class
;
78 AdgEntityClass
*entity_class
;
81 gobject_class
= (GObjectClass
*) klass
;
82 entity_class
= (AdgEntityClass
*) klass
;
84 g_type_class_add_private(klass
, sizeof(AdgToyTextPrivate
));
86 gobject_class
->finalize
= finalize
;
87 gobject_class
->get_property
= get_property
;
88 gobject_class
->set_property
= set_property
;
90 entity_class
->model_matrix_changed
= model_matrix_changed
;
91 entity_class
->invalidate
= invalidate
;
92 entity_class
->render
= render
;
94 g_object_class_override_property(gobject_class
, PROP_ORG
, "org");
96 param
= g_param_spec_string("label",
98 P_("The label to display"),
99 NULL
, G_PARAM_READWRITE
);
100 g_object_class_install_property(gobject_class
, PROP_LABEL
, param
);
104 adg_toy_text_init(AdgToyText
*toy_text
)
106 AdgToyTextPrivate
*priv
= G_TYPE_INSTANCE_GET_PRIVATE(toy_text
,
111 adg_point_unset(&priv
->org
);
112 priv
->org_pair
.x
= priv
->org_pair
.y
= 0.;
113 priv
->num_glyphs
= 0;
116 toy_text
->priv
= priv
;
120 positionable_init(AdgPositionableIface
*iface
)
126 org(AdgPositionable
*positionable
)
128 return & ((AdgToyText
*) positionable
)->priv
->org
;
132 finalize(GObject
*object
)
134 AdgToyText
*toy_text
= (AdgToyText
*) object
;
136 g_free(toy_text
->priv
->label
);
137 clear_label_cache(toy_text
);
139 ((GObjectClass
*) PARENT_CLASS
)->finalize(object
);
143 get_property(GObject
*object
, guint prop_id
, GValue
*value
, GParamSpec
*pspec
)
145 AdgToyText
*toy_text
= (AdgToyText
*) toy_text
;
149 g_value_set_boxed(value
, &toy_text
->priv
->org
);
152 g_value_set_string(value
, toy_text
->priv
->label
);
155 G_OBJECT_WARN_INVALID_PROPERTY_ID(object
, prop_id
, pspec
);
161 set_property(GObject
*object
, guint prop_id
,
162 const GValue
*value
, GParamSpec
*pspec
)
164 AdgToyText
*toy_text
= (AdgToyText
*) object
;
165 AdgToyTextPrivate
*priv
= toy_text
->priv
;
169 adg_point_copy(&priv
->org
, (AdgPoint
*) g_value_get_boxed(value
));
170 update_org_cache(toy_text
);
174 priv
->label
= g_value_dup_string(value
);
175 clear_label_cache(toy_text
);
178 G_OBJECT_WARN_INVALID_PROPERTY_ID(object
, prop_id
, pspec
);
186 * @label: the label text
188 * Creates a new toy text entity using @label as its text
190 * Return value: the new entity
193 adg_toy_text_new(const gchar
*label
)
195 return (AdgEntity
*) g_object_new(ADG_TYPE_TOY_TEXT
, "label", label
, NULL
);
199 * adg_toy_text_get_label:
200 * @toy_text: an #AdgToyText
202 * Gets the label text. The string is internally owned and
203 * must not be freed or modified.
205 * Return value: the label text
208 adg_toy_text_get_label(AdgToyText
*toy_text
)
210 g_return_val_if_fail(ADG_IS_TOY_TEXT(toy_text
), NULL
);
212 return toy_text
->priv
->label
;
216 * adg_toy_text_set_label:
217 * @toy_text: an #AdgToyText
218 * @label: the label text
220 * Explicitely sets the text to use as label.
223 adg_toy_text_set_label(AdgToyText
*toy_text
, const gchar
*label
)
225 g_return_if_fail(ADG_IS_TOY_TEXT(label
));
227 g_free(toy_text
->priv
->label
);
228 toy_text
->priv
->label
= g_strdup(label
);
229 g_object_notify((GObject
*) toy_text
, "label");
231 clear_label_cache(toy_text
);
236 render(AdgEntity
*entity
, cairo_t
*cr
)
238 AdgToyText
*toy_text
= (AdgToyText
*) entity
;
239 AdgToyTextPrivate
*priv
= toy_text
->priv
;
242 AdgStyle
*font_style
= adg_entity_get_style(entity
, ADG_SLOT_FONT_STYLE
);
243 cairo_set_matrix(cr
, adg_entity_get_paper_matrix(entity
));
244 adg_style_apply(font_style
, cr
);
247 update_label_cache(toy_text
, cr
);
248 update_org_cache(toy_text
);
251 cairo_show_glyphs(cr
, priv
->glyphs
, priv
->num_glyphs
);
254 PARENT_CLASS
->render(entity
, cr
);
258 model_matrix_changed(AdgEntity
*entity
, AdgMatrix
*parent_matrix
)
260 update_org_cache((AdgToyText
*) entity
);
261 PARENT_CLASS
->model_matrix_changed(entity
, parent_matrix
);
265 invalidate(AdgEntity
*entity
)
267 clear_label_cache((AdgToyText
*) entity
);
268 PARENT_CLASS
->invalidate(entity
);
272 update_org_cache(AdgToyText
*toy_text
)
274 AdgToyTextPrivate
*priv
= toy_text
->priv
;
275 AdgPoint
*org
= &toy_text
->priv
->org
;
276 AdgPair
*org_pair
= &toy_text
->priv
->org_pair
;
277 cairo_glyph_t
*glyph
;
282 org_pair
= &priv
->org_pair
;
283 glyph
= priv
->glyphs
;
284 cnt
= priv
->num_glyphs
;
286 if (glyph
== NULL
|| cnt
<= 0) {
287 /* No label cache to update: return */
291 adg_entity_point_to_paper_pair((AdgEntity
*) toy_text
, org
, org_pair
);
292 if (org_pair
->x
== glyph
->x
&& org_pair
->y
== glyph
->y
) {
293 /* The label is yet properly positioned */
297 x
= org_pair
->x
- glyph
->x
;
298 y
= org_pair
->y
- glyph
->y
;
308 update_label_cache(AdgToyText
*toy_text
, cairo_t
*cr
)
310 AdgToyTextPrivate
*priv
= toy_text
->priv
;
311 cairo_status_t status
;
313 status
= cairo_scaled_font_text_to_glyphs(cairo_get_scaled_font(cr
),
314 0., 0., priv
->label
, -1,
319 if (status
!= CAIRO_STATUS_SUCCESS
) {
320 g_error("Unable to build glyphs (cairo message: %s)",
321 cairo_status_to_string(status
));
325 cairo_glyph_extents(cr
, priv
->glyphs
, priv
->num_glyphs
, &priv
->extents
);
331 clear_label_cache(AdgToyText
*toy_text
)
333 AdgToyTextPrivate
*priv
= toy_text
->priv
;
336 cairo_glyph_free(priv
->glyphs
);
339 priv
->num_glyphs
= 0;
340 memset(&priv
->extents
, 0, sizeof(priv
->extents
));