1 /* ADG - Automatic Drawing Generation
2 * Copyright (C) 2007-2019 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.
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 * displacement of its content with an arbitrary fraction dependent
28 * on the content itself.
30 * This shift is computed by multiplying the #AdgAlignment:factor
31 * property with the extents of the bare content, with "bare" meaning
32 * the children entities as they are rendered on the global matrix
33 * *without* rotation components.
35 * To specify the alignment fraction, use adg_alignment_set_factor() and
36 * related methods or directly set the #AdgAlignment:factor property.
37 * For example, to center the children either in x and y, you can call
38 * adg_alignment_set_factor_explicit(alignment, 0.5, 0.5). To align them
39 * on the right, specify a (0, 1) factor.
47 * All fields are private and should not be used directly.
48 * Use its public methods instead.
54 #include "adg-internal.h"
55 #include "adg-entity.h"
56 #include "adg-container.h"
58 #include "adg-alignment.h"
59 #include "adg-alignment-private.h"
62 #define _ADG_OLD_ENTITY_CLASS ((AdgEntityClass *) adg_alignment_parent_class)
65 G_DEFINE_TYPE_WITH_PRIVATE(AdgAlignment
, adg_alignment
, ADG_TYPE_CONTAINER
)
73 static void _adg_get_property (GObject
*object
,
77 static void _adg_set_property (GObject
*object
,
81 static void _adg_arrange (AdgEntity
*entity
);
82 static void _adg_render (AdgEntity
*entity
,
87 adg_alignment_class_init(AdgAlignmentClass
*klass
)
89 GObjectClass
*gobject_class
;
90 AdgEntityClass
*entity_class
;
93 gobject_class
= (GObjectClass
*) klass
;
94 entity_class
= (AdgEntityClass
*) klass
;
96 gobject_class
->get_property
= _adg_get_property
;
97 gobject_class
->set_property
= _adg_set_property
;
99 entity_class
->arrange
= _adg_arrange
;
100 entity_class
->render
= _adg_render
;
102 param
= g_param_spec_boxed("factor",
104 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"),
107 g_object_class_install_property(gobject_class
, PROP_FACTOR
, param
);
111 adg_alignment_init(AdgAlignment
*alignment
)
113 AdgAlignmentPrivate
*data
= adg_alignment_get_instance_private(alignment
);
121 _adg_get_property(GObject
*object
, guint prop_id
,
122 GValue
*value
, GParamSpec
*pspec
)
124 AdgAlignmentPrivate
*data
= adg_alignment_get_instance_private((AdgAlignment
*) object
);
128 g_value_set_boxed(value
, &data
->factor
);
131 G_OBJECT_WARN_INVALID_PROPERTY_ID(object
, prop_id
, pspec
);
137 _adg_set_property(GObject
*object
, guint prop_id
,
138 const GValue
*value
, GParamSpec
*pspec
)
140 AdgAlignmentPrivate
*data
= adg_alignment_get_instance_private((AdgAlignment
*) object
);
141 const CpmlPair
*pair
;
145 pair
= g_value_get_boxed(value
);
146 if (! cpml_pair_equal(&data
->factor
, pair
)) {
147 cpml_pair_copy(&data
->factor
, pair
);
148 adg_entity_invalidate((AdgEntity
*) object
);
152 G_OBJECT_WARN_INVALID_PROPERTY_ID(object
, prop_id
, pspec
);
159 * @factor: the alignment factor
161 * Creates a new alignment container with the specified factor.
163 * Returns: the newly created alignment or <constant>NULL</constant> on errors.
168 adg_alignment_new(const CpmlPair
*factor
)
170 return g_object_new(ADG_TYPE_ALIGNMENT
, "factor", factor
, NULL
);
174 * adg_alignment_new_explicit:
175 * @x_factor: x component of the factor
176 * @y_factor: y component of the factor
178 * Convenient function that creates a new alignment accepting explicit
181 * Returns: the newly created alignment
186 adg_alignment_new_explicit(gdouble x_factor
, gdouble y_factor
)
193 return adg_alignment_new(&factor
);
197 * adg_alignment_set_factor:
198 * @alignment: an #AdgAlignment container
199 * @factor: the new factor
201 * Sets a the #AdgAlignment:factor property to @factor on @alignment.
202 * The factor is applied to the @alignment extents to compute the
203 * displacement of the content, providing a way to for instance center
204 * the content either vertically or horizontally. A pair factor
205 * of <constant>(0.5, 0)</constant> means the content will be centered
206 * horizontally in reference to the normal flow without @alignment.
211 adg_alignment_set_factor(AdgAlignment
*alignment
, const CpmlPair
*factor
)
213 g_return_if_fail(ADG_IS_ALIGNMENT(alignment
));
214 g_object_set(alignment
, "factor", factor
, NULL
);
218 * adg_alignment_set_factor_explicit:
219 * @alignment: an #AdgAlignment container
220 * @x_factor: x component of the factor
221 * @y_factor: y component of the factor
223 * Convenient wrapper around adg_alignment_set_factor() that accepts
224 * explicit factors instead of an #CpmlPair value.
229 adg_alignment_set_factor_explicit(AdgAlignment
*alignment
,
230 gdouble x_factor
, gdouble y_factor
)
237 adg_alignment_set_factor(alignment
, &factor
);
241 * adg_alignment_get_factor:
242 * @alignment: an #AdgAlignment container
244 * Gets the value of the #AdgAlignment:factor property. The returned
245 * pair is owned by @alignment and must not be modified or freed.
247 * Returns: the factor pair
252 adg_alignment_get_factor(AdgAlignment
*alignment
)
254 AdgAlignmentPrivate
*data
;
256 g_return_val_if_fail(ADG_IS_ALIGNMENT(alignment
), NULL
);
258 data
= adg_alignment_get_instance_private(alignment
);
260 return &data
->factor
;
265 _adg_arrange(AdgEntity
*entity
)
267 AdgAlignmentPrivate
*data
;
268 const CpmlExtents
*extents
;
269 CpmlExtents new_extents
;
270 cairo_matrix_t ctm
, ctm_inverted
, old_map
;
272 if (_ADG_OLD_ENTITY_CLASS
->arrange
== NULL
)
275 data
= adg_alignment_get_instance_private((AdgAlignment
*) entity
);
276 extents
= adg_entity_get_extents(entity
);
280 /* The shift is performed only when relevant */
281 if (data
->factor
.x
!= 0 || data
->factor
.y
!= 0) {
282 /* Force the ctm to be the identity matrix */
283 adg_matrix_copy(&old_map
, adg_entity_get_global_map(entity
));
284 adg_matrix_copy(&ctm
, adg_entity_get_global_map(entity
));
285 adg_matrix_transform(&ctm
, adg_entity_get_local_matrix(entity
),
286 ADG_TRANSFORM_AFTER
);
287 adg_matrix_copy(&ctm_inverted
, &ctm
);
288 cairo_matrix_invert(&ctm_inverted
);
289 adg_entity_transform_global_map(entity
, &ctm_inverted
,
290 ADG_TRANSFORM_AFTER
);
291 adg_entity_global_changed(entity
);
293 /* Calculating the shift */
294 _ADG_OLD_ENTITY_CLASS
->arrange(entity
);
295 extents
= adg_entity_get_extents(entity
);
296 if (extents
->is_defined
) {
297 data
->shift
.x
= -extents
->size
.x
* data
->factor
.x
;
298 data
->shift
.y
= -extents
->size
.y
* data
->factor
.y
;
299 cpml_vector_transform(&data
->shift
, &ctm
);
302 /* Restore the old global map */
303 adg_entity_set_global_map(entity
, &old_map
);
304 adg_entity_global_changed(entity
);
307 /* Add the shift to the extents */
308 _ADG_OLD_ENTITY_CLASS
->arrange(entity
);
309 cpml_extents_copy(&new_extents
, adg_entity_get_extents(entity
));
310 new_extents
.org
.x
+= data
->shift
.x
;
311 new_extents
.org
.y
+= data
->shift
.y
;
312 adg_entity_set_extents(entity
, &new_extents
);
316 _adg_render(AdgEntity
*entity
, cairo_t
*cr
)
318 AdgAlignmentPrivate
*data
;
320 if (_ADG_OLD_ENTITY_CLASS
->render
== NULL
)
323 data
= adg_alignment_get_instance_private((AdgAlignment
*) entity
);
325 cairo_translate(cr
, data
->shift
.x
, data
->shift
.y
);
326 _ADG_OLD_ENTITY_CLASS
->render(entity
, cr
);