[build] Moved project dirs under src/
[adg.git] / src / adg / adg-alignment.c
blobf977fd3b547851be277a1066ee62ea85381ae8d2
1 /* ADG - Automatic Drawing Generation
2 * Copyright (C) 2007,2008,2009,2010 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 **/
48 #include "adg-internal.h"
49 #include "adg-alignment.h"
50 #include "adg-alignment-private.h"
52 #define PARENT_ENTITY_CLASS ((AdgEntityClass *) adg_alignment_parent_class)
55 enum {
56 PROP_0,
57 PROP_FACTOR
60 static void get_property (GObject *object,
61 guint param_id,
62 GValue *value,
63 GParamSpec *pspec);
64 static void set_property (GObject *object,
65 guint prop_id,
66 const GValue *value,
67 GParamSpec *pspec);
68 static void arrange (AdgEntity *entity);
69 static gboolean set_factor (AdgAlignment *alignment,
70 const AdgPair *factor);
73 G_DEFINE_TYPE(AdgAlignment, adg_alignment, ADG_TYPE_CONTAINER);
76 static void
77 adg_alignment_class_init(AdgAlignmentClass *klass)
79 GObjectClass *gobject_class;
80 AdgEntityClass *entity_class;
81 GParamSpec *param;
83 gobject_class = (GObjectClass *) klass;
84 entity_class = (AdgEntityClass *) klass;
86 g_type_class_add_private(klass, sizeof(AdgAlignmentPrivate));
88 gobject_class->get_property = get_property;
89 gobject_class->set_property = set_property;
91 entity_class->arrange = arrange;
93 param = g_param_spec_boxed("factor",
94 P_("Factor"),
95 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"),
96 ADG_TYPE_PAIR,
97 G_PARAM_READWRITE);
98 g_object_class_install_property(gobject_class, PROP_FACTOR, param);
101 static void
102 adg_alignment_init(AdgAlignment *alignment)
104 AdgAlignmentPrivate *data = G_TYPE_INSTANCE_GET_PRIVATE(alignment,
105 ADG_TYPE_ALIGNMENT,
106 AdgAlignmentPrivate);
108 data->factor.x = 0;
109 data->factor.y = 0;
111 alignment->data = data;
114 static void
115 get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
117 AdgAlignmentPrivate *data = ((AdgAlignment *) object)->data;
119 switch (prop_id) {
120 case PROP_FACTOR:
121 g_value_set_boxed(value, &data->factor);
122 break;
123 default:
124 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
125 break;
129 static void
130 set_property(GObject *object,
131 guint prop_id, const GValue *value, GParamSpec *pspec)
133 AdgAlignment *alignment = (AdgAlignment *) object;
135 switch (prop_id) {
136 case PROP_FACTOR:
137 set_factor(alignment, g_value_get_boxed(value));
138 break;
139 default:
140 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
146 * adg_alignment_new:
147 * @factor: the alignment factor
149 * Creates a new alignment container with the specified factor.
151 * Returns: the newly created alignment or %NULL on errors
153 AdgAlignment *
154 adg_alignment_new(const AdgPair *factor)
156 return g_object_new(ADG_TYPE_ALIGNMENT, "factor", factor, NULL);
160 * adg_alignment_new_explicit:
161 * @x_factor: x component of the factor
162 * @y_factor: y component of the factor
164 * Convenient function that creates a new alignment accepting explicit
165 * factor values.
167 * Returns: the newly created alignment
169 AdgAlignment *
170 adg_alignment_new_explicit(gdouble x_factor, gdouble y_factor)
172 AdgPair factor;
174 factor.x = x_factor;
175 factor.y = y_factor;
177 return adg_alignment_new(&factor);
181 * adg_alignment_set_factor:
182 * @alignment: an #AdgAlignment container
183 * @factor: the new factor
185 * Sets a the #AdgAlignment:factor property to @factor on @alignment.
186 * The factor is applied to the @alignment extents to compute the
187 * displacement of the content, providing a way to for instance center
188 * the content either vertically or horizontally. A pair factor of
189 * (%0.5, %0) means the content will be centered horizontally in
190 * reference to the normal flow without @alignment.
192 void
193 adg_alignment_set_factor(AdgAlignment*alignment, const AdgPair *factor)
195 g_return_if_fail(ADG_IS_ALIGNMENT(alignment));
196 /* The factor == NULL condition is handled by set_factor() */
198 if (set_factor(alignment, factor))
199 g_object_notify((GObject *) alignment, "factor");
203 * adg_alignment_set_factor_explicit:
204 * @alignment: an #AdgAlignment container
205 * @x_factor: x component of the factor
206 * @y_factor: y component of the factor
208 * Convenient wrapper around adg_alignment_set_factor() that accepts
209 * explicit factors instead of an #AdgPair value.
211 void
212 adg_alignment_set_factor_explicit(AdgAlignment *alignment,
213 gdouble x_factor, gdouble y_factor)
215 AdgPair factor;
217 factor.x = x_factor;
218 factor.y = y_factor;
220 adg_alignment_set_factor(alignment, &factor);
224 * adg_alignment_get_factor:
225 * @alignment: an #AdgAlignment container
227 * Gets the value of the #AdgAlignment:factor property. The returned
228 * pair is owned by @alignment and must not be modified or freed.
230 * Returns: the factor pair
232 const AdgPair *
233 adg_alignment_get_factor(AdgAlignment *alignment)
235 AdgAlignmentPrivate *data;
237 g_return_val_if_fail(ADG_IS_ALIGNMENT(alignment), NULL);
239 data = alignment->data;
241 return &data->factor;
245 static void
246 arrange(AdgEntity *entity)
248 const CpmlExtents *extents;
249 AdgMatrix old_map;
251 adg_matrix_copy(&old_map, adg_entity_get_global_map(entity));
252 adg_entity_set_global_map(entity, adg_matrix_identity());
253 adg_entity_global_changed(entity);
255 if (PARENT_ENTITY_CLASS->arrange)
256 PARENT_ENTITY_CLASS->arrange(entity);
258 extents = adg_entity_get_extents(entity);
260 /* The children are displaced only if the extents are valid */
261 if (extents->is_defined) {
262 AdgAlignmentPrivate *data;
263 AdgMatrix map;
265 data = ((AdgAlignment *) entity)->data;
266 cairo_matrix_init_translate(&map,
267 -extents->size.x * data->factor.x,
268 -extents->size.y * data->factor.y);
269 adg_matrix_transform(&map, &old_map, ADG_TRANSFORM_AFTER);
271 adg_entity_set_global_map(entity, &map);
272 adg_entity_global_changed(entity);
274 /* Here there is room for improvements: this second arrange()
275 * phase could probably be avoided... */
276 if (PARENT_ENTITY_CLASS->arrange)
277 PARENT_ENTITY_CLASS->arrange(entity);
280 adg_entity_set_global_map(entity, &old_map);
283 static gboolean
284 set_factor(AdgAlignment *alignment, const AdgPair *factor)
286 AdgAlignmentPrivate *data;
288 g_return_val_if_fail(factor != NULL, FALSE);
290 data = alignment->data;
292 if (adg_pair_equal(&data->factor, factor))
293 return FALSE;
295 data->factor = *factor;
297 return TRUE;