[AdgAlignment] Use an helper pair instead of abuse the global map
[adg.git] / src / adg / adg-alignment.c
bloba329431cbbd9b8a3c8fc8d118fe01575c929c108
1 /* ADG - Automatic Drawing Generation
2 * Copyright (C) 2007,2008,2009,2010,2011 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-alignment
23 * @short_description: Base class for entity that can contain other entities
25 * The #AdgAlignment is an entity that can contains more sub-entities,
26 * much in the same way as the #AdgContainer does, but allowing the
27 * alignment of the content with an arbitrary fraction of the boundaring
28 * box of the content itsself.
30 * To specify the alignment fraction, use adg_alignment_set_factor() and
31 * related methods or directly set the #AdgAlignment:factor property.
32 * For example, to center the children either in x and y, you can call
33 * adg_alignment_set_factor_explicit(alignment, 0.5, 0.5). To align them
34 * on the right, specify a (0, 1) factor.
35 **/
37 /**
38 * AdgAlignment:
40 * All fields are private and should not be used directly.
41 * Use its public methods instead.
42 **/
45 #include "adg-internal.h"
46 #include "adg-entity.h"
47 #include "adg-container.h"
49 #include "adg-alignment.h"
50 #include "adg-alignment-private.h"
53 #define _ADG_OLD_ENTITY_CLASS ((AdgEntityClass *) adg_alignment_parent_class)
56 G_DEFINE_TYPE(AdgAlignment, adg_alignment, ADG_TYPE_CONTAINER)
58 enum {
59 PROP_0,
60 PROP_FACTOR
64 static void _adg_get_property (GObject *object,
65 guint param_id,
66 GValue *value,
67 GParamSpec *pspec);
68 static void _adg_set_property (GObject *object,
69 guint prop_id,
70 const GValue *value,
71 GParamSpec *pspec);
72 static void _adg_arrange (AdgEntity *entity);
73 static void _adg_render (AdgEntity *entity,
74 cairo_t *cr);
77 static void
78 adg_alignment_class_init(AdgAlignmentClass *klass)
80 GObjectClass *gobject_class;
81 AdgEntityClass *entity_class;
82 GParamSpec *param;
84 gobject_class = (GObjectClass *) klass;
85 entity_class = (AdgEntityClass *) klass;
87 g_type_class_add_private(klass, sizeof(AdgAlignmentPrivate));
89 gobject_class->get_property = _adg_get_property;
90 gobject_class->set_property = _adg_set_property;
92 entity_class->arrange = _adg_arrange;
93 entity_class->render = _adg_render;
95 param = g_param_spec_boxed("factor",
96 P_("Factor"),
97 P_("Portion of extents, either in x and y, the content will be displaced: a (0.5, 0.5) factor means the origin is the middle point of the extents"),
98 ADG_TYPE_PAIR,
99 G_PARAM_READWRITE);
100 g_object_class_install_property(gobject_class, PROP_FACTOR, param);
103 static void
104 adg_alignment_init(AdgAlignment *alignment)
106 AdgAlignmentPrivate *data = G_TYPE_INSTANCE_GET_PRIVATE(alignment,
107 ADG_TYPE_ALIGNMENT,
108 AdgAlignmentPrivate);
110 data->factor.x = 0;
111 data->factor.y = 0;
112 data->displacement.x = 0;
113 data->displacement.y = 0;
115 alignment->data = data;
118 static void
119 _adg_get_property(GObject *object, guint prop_id,
120 GValue *value, GParamSpec *pspec)
122 AdgAlignmentPrivate *data = ((AdgAlignment *) object)->data;
124 switch (prop_id) {
125 case PROP_FACTOR:
126 g_value_set_boxed(value, &data->factor);
127 break;
128 default:
129 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
130 break;
134 static void
135 _adg_set_property(GObject *object, guint prop_id,
136 const GValue *value, GParamSpec *pspec)
138 AdgAlignmentPrivate *data;
139 const AdgPair *pair;
141 data = ((AdgAlignment *) object)->data;
143 switch (prop_id) {
144 case PROP_FACTOR:
145 pair = g_value_get_boxed(value);
146 if (! cpml_pair_equal(&data->factor, pair)) {
147 adg_pair_copy(&data->factor, pair);
148 adg_entity_invalidate((AdgEntity *) object);
150 break;
151 default:
152 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
158 * adg_alignment_new:
159 * @factor: the alignment factor
161 * Creates a new alignment container with the specified factor.
163 * Returns: the newly created alignment or %NULL on errors
165 AdgAlignment *
166 adg_alignment_new(const AdgPair *factor)
168 return g_object_new(ADG_TYPE_ALIGNMENT, "factor", factor, NULL);
172 * adg_alignment_new_explicit:
173 * @x_factor: x component of the factor
174 * @y_factor: y component of the factor
176 * Convenient function that creates a new alignment accepting explicit
177 * factor values.
179 * Returns: the newly created alignment
181 AdgAlignment *
182 adg_alignment_new_explicit(gdouble x_factor, gdouble y_factor)
184 AdgPair factor;
186 factor.x = x_factor;
187 factor.y = y_factor;
189 return adg_alignment_new(&factor);
193 * adg_alignment_set_factor:
194 * @alignment: an #AdgAlignment container
195 * @factor: the new factor
197 * Sets a the #AdgAlignment:factor property to @factor on @alignment.
198 * The factor is applied to the @alignment extents to compute the
199 * displacement of the content, providing a way to for instance center
200 * the content either vertically or horizontally. A pair factor of
201 * (%0.5, %0) means the content will be centered horizontally in
202 * reference to the normal flow without @alignment.
204 void
205 adg_alignment_set_factor(AdgAlignment *alignment, const AdgPair *factor)
207 g_return_if_fail(ADG_IS_ALIGNMENT(alignment));
208 g_object_set(alignment, "factor", factor, NULL);
212 * adg_alignment_set_factor_explicit:
213 * @alignment: an #AdgAlignment container
214 * @x_factor: x component of the factor
215 * @y_factor: y component of the factor
217 * Convenient wrapper around adg_alignment_set_factor() that accepts
218 * explicit factors instead of an #AdgPair value.
220 void
221 adg_alignment_set_factor_explicit(AdgAlignment *alignment,
222 gdouble x_factor, gdouble y_factor)
224 AdgPair factor;
226 factor.x = x_factor;
227 factor.y = y_factor;
229 adg_alignment_set_factor(alignment, &factor);
233 * adg_alignment_get_factor:
234 * @alignment: an #AdgAlignment container
236 * Gets the value of the #AdgAlignment:factor property. The returned
237 * pair is owned by @alignment and must not be modified or freed.
239 * Returns: the factor pair
241 const AdgPair *
242 adg_alignment_get_factor(AdgAlignment *alignment)
244 AdgAlignmentPrivate *data;
246 g_return_val_if_fail(ADG_IS_ALIGNMENT(alignment), NULL);
248 data = alignment->data;
250 return &data->factor;
254 static void
255 _adg_arrange(AdgEntity *entity)
257 AdgAlignmentPrivate *data;
258 const CpmlExtents *extents;
260 if (_ADG_OLD_ENTITY_CLASS->arrange != NULL)
261 _ADG_OLD_ENTITY_CLASS->arrange(entity);
263 data = ((AdgAlignment *) entity)->data;
264 extents = adg_entity_get_extents(entity);
266 /* The children are displaced only if the extents are valid */
267 if (extents->is_defined) {
268 const AdgMatrix *global;
269 AdgMatrix unglobal;
270 CpmlExtents new_extents;
272 global = adg_entity_get_global_matrix(entity);
273 adg_matrix_copy(&unglobal, global);
274 cairo_matrix_invert(&unglobal);
275 data->displacement = extents->size;
277 cpml_vector_transform(&data->displacement, &unglobal);
279 /* The alignment is computed on the absolute size
280 * of the bare entity (with bare meaning the entity
281 * as it was rendered on an identity matrix) */
282 if (data->displacement.x < 0)
283 data->displacement.x = -data->displacement.x;
284 if (data->displacement.y < 0)
285 data->displacement.y = -data->displacement.y;
287 data->displacement.x *= -data->factor.x;
288 data->displacement.y *= -data->factor.y;
290 cpml_vector_transform(&data->displacement, global);
292 cpml_extents_copy(&new_extents, extents);
293 new_extents.org.x += data->displacement.x;
294 new_extents.org.y += data->displacement.y;
295 adg_entity_set_extents(entity, &new_extents);
296 } else {
297 data->displacement.x = 0;
298 data->displacement.y = 0;
302 static void
303 _adg_render(AdgEntity *entity, cairo_t *cr)
305 AdgAlignmentPrivate *data;
307 if (_ADG_OLD_ENTITY_CLASS->render == NULL)
308 return;
310 data = ((AdgAlignment *) entity)->data;
312 cairo_translate(cr, data->displacement.x, data->displacement.y);
313 _ADG_OLD_ENTITY_CLASS->render(entity, cr);