[docs] Updated TODO.xml
[adg.git] / adg / adg-alignment.c
blobf437ed8d95c25d025547590ca867c9a575f18119
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-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.
36 * The displacement is done by modifing the global matrix at the end of
37 * the arrange method.
38 **/
40 /**
41 * AdgAlignment:
43 * All fields are private and should not be used directly.
44 * Use its public methods instead.
45 **/
47 #include "adg-alignment.h"
48 #include "adg-alignment-private.h"
49 #include "adg-intl.h"
51 #define PARENT_ENTITY_CLASS ((AdgEntityClass *) adg_alignment_parent_class)
54 enum {
55 PROP_0,
56 PROP_FACTOR
59 static void get_property (GObject *object,
60 guint param_id,
61 GValue *value,
62 GParamSpec *pspec);
63 static void set_property (GObject *object,
64 guint prop_id,
65 const GValue *value,
66 GParamSpec *pspec);
67 static void arrange (AdgEntity *entity);
68 static gboolean set_factor (AdgAlignment *alignment,
69 const AdgPair *factor);
72 G_DEFINE_TYPE(AdgAlignment, adg_alignment, ADG_TYPE_CONTAINER);
75 static void
76 adg_alignment_class_init(AdgAlignmentClass *klass)
78 GObjectClass *gobject_class;
79 AdgEntityClass *entity_class;
80 GParamSpec *param;
82 gobject_class = (GObjectClass *) klass;
83 entity_class = (AdgEntityClass *) klass;
85 g_type_class_add_private(klass, sizeof(AdgAlignmentPrivate));
87 gobject_class->get_property = get_property;
88 gobject_class->set_property = set_property;
90 entity_class->arrange = arrange;
92 param = g_param_spec_boxed("factor",
93 P_("Factor"),
94 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"),
95 ADG_TYPE_PAIR,
96 G_PARAM_READWRITE);
97 g_object_class_install_property(gobject_class, PROP_FACTOR, param);
100 static void
101 adg_alignment_init(AdgAlignment *alignment)
103 AdgAlignmentPrivate *data = G_TYPE_INSTANCE_GET_PRIVATE(alignment,
104 ADG_TYPE_ALIGNMENT,
105 AdgAlignmentPrivate);
107 data->factor.x = 0;
108 data->factor.y = 0;
110 alignment->data = data;
113 static void
114 get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
116 AdgAlignmentPrivate *data = ((AdgAlignment *) object)->data;
118 switch (prop_id) {
119 case PROP_FACTOR:
120 g_value_set_boxed(value, &data->factor);
121 break;
122 default:
123 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
124 break;
128 static void
129 set_property(GObject *object,
130 guint prop_id, const GValue *value, GParamSpec *pspec)
132 AdgAlignment *alignment = (AdgAlignment *) object;
134 switch (prop_id) {
135 case PROP_FACTOR:
136 set_factor(alignment, g_value_get_boxed(value));
137 break;
138 default:
139 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
145 * adg_alignment_new:
146 * @factor: the alignment factor
148 * Creates a new alignment container with the specified factor.
150 * Returns: the newly created alignment
152 AdgAlignment *
153 adg_alignment_new(const AdgPair *factor)
155 return g_object_new(ADG_TYPE_ALIGNMENT, "factor", factor, NULL);
159 * adg_alignment_new_explicit:
160 * @x_factor: x component of the factor
161 * @y_factor: y component of the factor
163 * Convenient function that creates a new alignment accepting explicit
164 * factor values.
166 * Returns: the newly created alignment
168 AdgAlignment *
169 adg_alignment_new_explicit(gdouble x_factor, gdouble y_factor)
171 AdgPair factor;
173 factor.x = x_factor;
174 factor.y = y_factor;
176 return adg_alignment_new(&factor);
180 * adg_alignment_set_factor:
181 * @alignment: an #AdgAlignment container
182 * @factor: the new factor
184 * Sets a the #AdgAlignment:factor property to @factor on @alignment.
185 * The factor is applied to the @alignment extents to compute the
186 * displacement of the content, providing a way to for instance center
187 * the content either vertically or horizontally. A pair factor of
188 * (%0.5, %0) means the content will be centered horizontally in
189 * reference to the normal flow without @alignment.
191 void
192 adg_alignment_set_factor(AdgAlignment*alignment, const AdgPair *factor)
194 g_return_if_fail(ADG_IS_ALIGNMENT(alignment));
195 g_return_if_fail(factor != NULL);
197 if (set_factor(alignment, factor))
198 g_object_notify((GObject *) alignment, "factor");
202 * adg_alignment_set_factor_explicit:
203 * @alignment: an #AdgAlignment container
204 * @x_factor: x component of the factor
205 * @y_factor: y component of the factor
207 * Convenient wrapper around adg_alignment_set_factor() that accepts
208 * explicit factors instead of an #AdgPair value.
210 void
211 adg_alignment_set_factor_explicit(AdgAlignment *alignment,
212 gdouble x_factor, gdouble y_factor)
214 AdgPair factor;
216 factor.x = x_factor;
217 factor.y = y_factor;
219 adg_alignment_set_factor(alignment, &factor);
223 * adg_alignment_get_factor:
224 * @alignment: an #AdgAlignment container
226 * Gets the value of the #AdgAlignment:factor property. The returned
227 * pair is owned by @alignment and must not be modified or freed.
229 * Returns: the factor pair
231 const AdgPair *
232 adg_alignment_get_factor(AdgAlignment *alignment)
234 AdgAlignmentPrivate *data;
236 g_return_val_if_fail(ADG_IS_ALIGNMENT(alignment), NULL);
238 data = alignment->data;
240 return &data->factor;
244 static void
245 arrange(AdgEntity *entity)
247 const CpmlExtents *extents;
248 AdgMatrix old_map;
250 adg_matrix_copy(&old_map, adg_entity_get_global_map(entity));
251 adg_entity_set_global_map(entity, adg_matrix_identity());
252 adg_entity_global_changed(entity);
254 if (PARENT_ENTITY_CLASS->arrange)
255 PARENT_ENTITY_CLASS->arrange(entity);
257 extents = adg_entity_get_extents(entity);
259 /* The children are displaced only if the extents are valid */
260 if (extents->is_defined) {
261 AdgAlignmentPrivate *data;
262 AdgMatrix map;
264 data = ((AdgAlignment *) entity)->data;
265 cairo_matrix_init_translate(&map,
266 -extents->size.x * data->factor.x,
267 -extents->size.y * data->factor.y);
268 adg_matrix_transform(&map, &old_map, ADG_TRANSFORM_AFTER);
270 adg_entity_set_global_map(entity, &map);
271 adg_entity_global_changed(entity);
273 /* Here there is room for improvements: this second arrange()
274 * phase could probably be avoided... */
275 if (PARENT_ENTITY_CLASS->arrange)
276 PARENT_ENTITY_CLASS->arrange(entity);
279 adg_entity_set_global_map(entity, &old_map);
282 static gboolean
283 set_factor(AdgAlignment *alignment, const AdgPair *factor)
285 AdgAlignmentPrivate *data = alignment->data;
287 if (adg_pair_equal(&data->factor, factor))
288 return FALSE;
290 data->factor = *factor;
292 return TRUE;