[AdgAlignment] Properly set the extents
[adg.git] / adg / adg-alignment.c
blobb9937f5e15f849cb78755bcd221eedf2713bf1ff
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 * Moreover, it can apply a common transformation to local and/or global
27 * maps: see http://adg.entidi.com/tutorial/view/3 for further details.
28 **/
30 /**
31 * AdgAlignment:
33 * All fields are private and should not be used directly.
34 * Use its public methods instead.
35 **/
37 #include "adg-alignment.h"
38 #include "adg-alignment-private.h"
39 #include "adg-entity-private.h"
40 #include "adg-intl.h"
42 #define PARENT_ENTITY_CLASS ((AdgEntityClass *) adg_alignment_parent_class)
45 enum {
46 PROP_0,
47 PROP_FACTOR
51 static void get_property (GObject *object,
52 guint param_id,
53 GValue *value,
54 GParamSpec *pspec);
55 static void set_property (GObject *object,
56 guint prop_id,
57 const GValue *value,
58 GParamSpec *pspec);
59 static void global_changed (AdgEntity *entity);
60 static void arrange (AdgEntity *entity);
61 static gboolean set_factor (AdgAlignment *alignment,
62 const AdgPair *factor);
65 G_DEFINE_TYPE(AdgAlignment, adg_alignment, ADG_TYPE_CONTAINER);
68 static void
69 adg_alignment_class_init(AdgAlignmentClass *klass)
71 GObjectClass *gobject_class;
72 AdgEntityClass *entity_class;
73 GParamSpec *param;
75 gobject_class = (GObjectClass *) klass;
76 entity_class = (AdgEntityClass *) klass;
78 g_type_class_add_private(klass, sizeof(AdgAlignmentPrivate));
80 gobject_class->get_property = get_property;
81 gobject_class->set_property = set_property;
83 entity_class->global_changed = global_changed;
84 entity_class->arrange = arrange;
86 param = g_param_spec_boxed("factor",
87 P_("Factor"),
88 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"),
89 ADG_TYPE_PAIR,
90 G_PARAM_WRITABLE);
91 g_object_class_install_property(gobject_class, PROP_FACTOR, param);
94 static void
95 adg_alignment_init(AdgAlignment *alignment)
97 AdgAlignmentPrivate *data = G_TYPE_INSTANCE_GET_PRIVATE(alignment,
98 ADG_TYPE_ALIGNMENT,
99 AdgAlignmentPrivate);
101 data->factor.x = 0;
102 data->factor.y = 0;
104 alignment->data = data;
107 static void
108 get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
110 AdgAlignmentPrivate *data = ((AdgAlignment *) object)->data;
112 switch (prop_id) {
113 case PROP_FACTOR:
114 g_value_set_boxed(value, &data->factor);
115 break;
116 default:
117 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
118 break;
122 static void
123 set_property(GObject *object,
124 guint prop_id, const GValue *value, GParamSpec *pspec)
126 AdgAlignment *alignment = (AdgAlignment *) object;
128 switch (prop_id) {
129 case PROP_FACTOR:
130 set_factor(alignment, g_value_get_boxed(value));
131 break;
132 default:
133 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
139 * adg_alignment_new:
140 * @factor: the alignment factor
142 * Creates a new alignment container with the specified factor.
144 * Returns: the newly created alignment
146 AdgAlignment *
147 adg_alignment_new(const AdgPair *factor)
149 return g_object_new(ADG_TYPE_ALIGNMENT, "factor", factor, NULL);
153 * adg_alignment_new_explicit:
154 * @x_factor: x component of the factor
155 * @y_factor: y component of the factor
157 * Convenient function that creates a new alignment accepting explicit
158 * factor values.
160 * Returns: the newly created alignment
162 AdgAlignment *
163 adg_alignment_new_explicit(gdouble x_factor, gdouble y_factor)
165 AdgPair factor;
167 factor.x = x_factor;
168 factor.y = y_factor;
170 return adg_alignment_new(&factor);
174 * adg_alignment_get_factor:
175 * @alignment: an #AdgAlignment container
177 * Gets the value of the #AdgAlignment:factor property. The returned
178 * pair is owned by @alignment and must not be modified or freed.
180 * Returns: the factor pair
182 const AdgPair *
183 adg_alignment_get_factor(AdgAlignment *alignment)
185 AdgAlignmentPrivate *data;
187 g_return_val_if_fail(ADG_IS_ALIGNMENT(alignment), NULL);
189 data = alignment->data;
191 return &data->factor;
195 * adg_alignment_set_factor:
196 * @alignment: an #AdgAlignment container
197 * @factor: the new factor
199 * Sets a the #AdgAlignment:factor property to @factor on @alignment.
200 * The factor is applied to the @alignment extents to compute the
201 * displacement of the content, providing a way to for instance center
202 * the content either vertically or horizontally. A pair factor of
203 * (%0.5, %0) means the content will be centered horizontally in
204 * reference to the normal flow without @alignment.
206 void
207 adg_alignment_set_factor(AdgAlignment*alignment, const AdgPair *factor)
209 g_return_if_fail(ADG_IS_ALIGNMENT(alignment));
210 g_return_if_fail(factor != NULL);
212 if (set_factor(alignment, factor))
213 g_object_notify((GObject *) alignment, "factor");
217 * adg_alignment_set_factor_explicit:
218 * @alignment: an #AdgAlignment container
219 * @x_factor: x component of the factor
220 * @y_factor: y component of the factor
222 * Convenient wrapper around adg_alignment_set_factor() that accepts
223 * explicit factors instead of an #AdgPair value.
225 void
226 adg_alignment_set_factor_explicit(AdgAlignment *alignment,
227 gdouble x_factor, gdouble y_factor)
229 AdgPair factor;
231 factor.x = x_factor;
232 factor.y = y_factor;
234 adg_alignment_set_factor(alignment, &factor);
238 static void
239 global_changed(AdgEntity *entity)
241 AdgEntityClass *entity_class;
242 AdgEntityPrivate *entity_data;
243 CpmlExtents *extents;
244 AdgMatrix *global;
245 AdgPair shift;
247 entity_class = g_type_class_ref(ADG_TYPE_ENTITY);
248 entity_data = entity->data;
249 extents = &entity_data->extents;
250 global = &entity_data->global_matrix;
252 if (extents->is_defined) {
253 /* The entities are displaced only if the extents are valid */
254 AdgAlignmentPrivate *data = ((AdgAlignment *) entity)->data;
256 cpml_pair_copy(&shift, &extents->size);
257 cpml_pair_mul(&shift, &data->factor);
259 cpml_pair_sub(&extents->org, &shift);
260 } else {
261 shift.x = 0;
262 shift.y = 0;
265 if (entity_class->global_changed != NULL)
266 entity_class->global_changed(entity);
268 g_type_class_unref(entity_class);
270 /* The real job: temporarily modify the global matrix
271 * to align the contained entities */
272 global->x0 -= shift.x;
273 global->y0 -= shift.y;
275 adg_container_propagate_by_name((AdgContainer *) entity, "global-changed");
277 global->x0 += shift.x;
278 global->y0 += shift.y;
281 static void
282 arrange(AdgEntity *entity)
284 PARENT_ENTITY_CLASS->arrange(entity);
286 /* Force a recomputation of the children position */
287 adg_entity_global_changed(entity);
290 static gboolean
291 set_factor(AdgAlignment *alignment, const AdgPair *factor)
293 AdgAlignmentPrivate *data = alignment->data;
295 if (adg_pair_equal(&data->factor, factor))
296 return FALSE;
298 data->factor = *factor;
300 return TRUE;