adg: correct adg_canvas_autoscale() bug
[adg.git] / src / adg / adg-canvas.c
blobee0f05fa806c116b01571a186f148677e058f9d8
1 /* ADG - Automatic Drawing Generation
2 * Copyright (C) 2007,2008,2009,2010,2011,2012,2013 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-canvas
23 * @short_description: The drawing container
25 * The canvas is the toplevel entity of an ADG drawing. It can be
26 * bound to a GTK+ widget, such as #AdgGtkArea, or manually rendered
27 * to a custom surface.
29 * Tipically, the canvas contains the description and properties of
30 * the media used, such as such as size (if relevant), margins,
31 * border and paddings. This approach clearly follows the block model
32 * of the CSS specifications level 2.
34 * The paddings specify the distance between the entities contained
35 * by the canvas and the border. The margins specify the distance
36 * between the canvas border and the media extents.
38 * The canvas (hence the media) size can be explicitely specified
39 * by directly writing to the #AdgCanvas:size property or using any
40 * valid setter, such as adg_canvas_set_size(),
41 * adg_canvas_set_size_explicit() or the convenient
42 * adg_canvas_set_paper() GTK+ wrapper. You can also set explicitely
43 * only one dimension and let the other one be computed automatically.
44 * This is done by using the special value 0 that specifies a side
45 * must be autocalculated.
47 * By default either width and height must be autocalculated (are
48 * set to 0), so the arrange() phase on the canvas is performed.
49 * Margins and paddings are then added to the extents to get the
50 * border coordinates and the final bounding box.
52 * When the size is explicitely set, instead, the final bounding
53 * box is forcibly set to this value without taking the canvas
54 * extents into account. The margins are then subtracted to get
55 * the coordinates of the border. In this case, the paddings are
56 * simply ignored.
58 * Since: 1.0
59 **/
61 /**
62 * AdgCanvas:
64 * All fields are private and should not be used directly.
65 * Use its public methods instead.
67 * Since: 1.0
68 **/
71 #include "adg-internal.h"
72 #if GTK3_ENABLED || GTK2_ENABLED
73 #include <gtk/gtk.h>
74 #endif
76 #include "adg-container.h"
77 #include "adg-table.h"
78 #include "adg-title-block.h"
79 #include "adg-style.h"
80 #include "adg-color-style.h"
81 #include "adg-dress.h"
82 #include "adg-param-dress.h"
84 #include <adg-canvas.h>
85 #include "adg-canvas-private.h"
88 #define _ADG_OLD_OBJECT_CLASS ((GObjectClass *) adg_canvas_parent_class)
89 #define _ADG_OLD_ENTITY_CLASS ((AdgEntityClass *) adg_canvas_parent_class)
92 G_DEFINE_TYPE(AdgCanvas, adg_canvas, ADG_TYPE_CONTAINER)
94 enum {
95 PROP_0,
96 PROP_SIZE,
97 PROP_SCALES,
98 PROP_BACKGROUND_DRESS,
99 PROP_FRAME_DRESS,
100 PROP_TITLE_BLOCK,
101 PROP_TOP_MARGIN,
102 PROP_RIGHT_MARGIN,
103 PROP_BOTTOM_MARGIN,
104 PROP_LEFT_MARGIN,
105 PROP_HAS_FRAME,
106 PROP_TOP_PADDING,
107 PROP_RIGHT_PADDING,
108 PROP_BOTTOM_PADDING,
109 PROP_LEFT_PADDING
113 static void _adg_dispose (GObject *object);
114 static void _adg_get_property (GObject *object,
115 guint param_id,
116 GValue *value,
117 GParamSpec *pspec);
118 static void _adg_set_property (GObject *object,
119 guint param_id,
120 const GValue *value,
121 GParamSpec *pspec);
122 static void _adg_global_changed (AdgEntity *entity);
123 static void _adg_local_changed (AdgEntity *entity);
124 static void _adg_invalidate (AdgEntity *entity);
125 static void _adg_arrange (AdgEntity *entity);
126 static void _adg_render (AdgEntity *entity,
127 cairo_t *cr);
130 static void
131 adg_canvas_class_init(AdgCanvasClass *klass)
133 GObjectClass *gobject_class;
134 AdgEntityClass *entity_class;
135 GParamSpec *param;
137 gobject_class = (GObjectClass *) klass;
138 entity_class = (AdgEntityClass *) klass;
140 g_type_class_add_private(klass, sizeof(AdgCanvasPrivate));
142 gobject_class->dispose = _adg_dispose;
143 gobject_class->get_property = _adg_get_property;
144 gobject_class->set_property = _adg_set_property;
146 entity_class->global_changed = _adg_global_changed;
147 entity_class->local_changed = _adg_local_changed;
148 entity_class->invalidate = _adg_invalidate;
149 entity_class->arrange = _adg_arrange;
150 entity_class->render = _adg_render;
152 param = g_param_spec_boxed("size",
153 P_("Canvas Size"),
154 P_("The size set on this canvas: use 0 to have an automatic dimension based on the canvas extents"),
155 CPML_TYPE_PAIR,
156 G_PARAM_READWRITE);
157 g_object_class_install_property(gobject_class, PROP_SIZE, param);
159 param = g_param_spec_boxed("scales",
160 P_("Valid Scales"),
161 P_("List of scales to be tested while autoscaling the drawing"),
162 G_TYPE_STRV,
163 G_PARAM_READWRITE);
164 g_object_class_install_property(gobject_class, PROP_SCALES, param);
166 param = adg_param_spec_dress("background-dress",
167 P_("Background Dress"),
168 P_("The color dress to use for the canvas background"),
169 ADG_DRESS_COLOR_BACKGROUND,
170 G_PARAM_READWRITE);
171 g_object_class_install_property(gobject_class, PROP_BACKGROUND_DRESS, param);
173 param = adg_param_spec_dress("frame-dress",
174 P_("Frame Dress"),
175 P_("Line dress to use while drawing the frame around the canvas"),
176 ADG_DRESS_LINE_FRAME,
177 G_PARAM_READWRITE);
178 g_object_class_install_property(gobject_class, PROP_FRAME_DRESS, param);
180 param = g_param_spec_object("title-block",
181 P_("Title Block"),
182 P_("The title block to assign to this canvas"),
183 ADG_TYPE_TITLE_BLOCK,
184 G_PARAM_READWRITE);
185 g_object_class_install_property(gobject_class, PROP_TITLE_BLOCK, param);
187 param = g_param_spec_double("top-margin",
188 P_("Top Margin"),
189 P_("The margin (in global space) to leave above the frame"),
190 -G_MAXDOUBLE, G_MAXDOUBLE, 15,
191 G_PARAM_READWRITE);
192 g_object_class_install_property(gobject_class, PROP_TOP_MARGIN, param);
194 param = g_param_spec_double("right-margin",
195 P_("Right Margin"),
196 P_("The margin (in global space) to leave empty at the right of the frame"),
197 -G_MAXDOUBLE, G_MAXDOUBLE, 15,
198 G_PARAM_READWRITE);
199 g_object_class_install_property(gobject_class, PROP_RIGHT_MARGIN, param);
201 param = g_param_spec_double("bottom-margin",
202 P_("Bottom Margin"),
203 P_("The margin (in global space) to leave empty below the frame"),
204 -G_MAXDOUBLE, G_MAXDOUBLE, 15,
205 G_PARAM_READWRITE);
206 g_object_class_install_property(gobject_class, PROP_BOTTOM_MARGIN, param);
208 param = g_param_spec_double("left-margin",
209 P_("Left Margin"),
210 P_("The margin (in global space) to leave empty at the left of the frame"),
211 -G_MAXDOUBLE, G_MAXDOUBLE, 15,
212 G_PARAM_READWRITE);
213 g_object_class_install_property(gobject_class, PROP_LEFT_MARGIN, param);
215 param = g_param_spec_boolean("has-frame",
216 P_("Has Frame Flag"),
217 P_("If enabled, a frame using the frame dress will be drawn around the canvas extents, taking into account the margins"),
218 TRUE,
219 G_PARAM_READWRITE);
220 g_object_class_install_property(gobject_class, PROP_HAS_FRAME, param);
222 param = g_param_spec_double("top-padding",
223 P_("Top Padding"),
224 P_("The padding (in global space) to leave empty above between the drawing and the frame"),
225 -G_MAXDOUBLE, G_MAXDOUBLE, 15,
226 G_PARAM_READWRITE);
227 g_object_class_install_property(gobject_class, PROP_TOP_PADDING, param);
229 param = g_param_spec_double("right-padding",
230 P_("Right Padding"),
231 P_("The padding (in global space) to leave empty at the right between the drawing and the frame"),
232 -G_MAXDOUBLE, G_MAXDOUBLE, 15,
233 G_PARAM_READWRITE);
234 g_object_class_install_property(gobject_class, PROP_RIGHT_PADDING, param);
236 param = g_param_spec_double("bottom-padding",
237 P_("Bottom Padding"),
238 P_("The padding (in global space) to leave empty below between the drawing and the frame"),
239 -G_MAXDOUBLE, G_MAXDOUBLE, 15,
240 G_PARAM_READWRITE);
241 g_object_class_install_property(gobject_class, PROP_BOTTOM_PADDING, param);
243 param = g_param_spec_double("left-padding",
244 P_("Left Padding"),
245 P_("The padding (in global space) to leave empty at the left between the drawing and the frame"),
246 -G_MAXDOUBLE, G_MAXDOUBLE, 15,
247 G_PARAM_READWRITE);
248 g_object_class_install_property(gobject_class, PROP_LEFT_PADDING, param);
251 static void
252 adg_canvas_init(AdgCanvas *canvas)
254 AdgCanvasPrivate *data = G_TYPE_INSTANCE_GET_PRIVATE(canvas,
255 ADG_TYPE_CANVAS,
256 AdgCanvasPrivate);
257 const gchar *scales[] = {
258 "10:1", "5:1", "3:1", "2:1", "1:1", "1:2", "1:3", "1:5", "1:10",
259 NULL
263 data->size.x = 0;
264 data->size.y = 0;
265 data->scales = g_strdupv((gchar **) scales);
266 data->background_dress = ADG_DRESS_COLOR_BACKGROUND;
267 data->frame_dress = ADG_DRESS_LINE_FRAME;
268 data->title_block = NULL;
269 data->top_margin = 15;
270 data->right_margin = 15;
271 data->bottom_margin = 15;
272 data->left_margin = 15;
273 data->has_frame = TRUE;
274 data->top_padding = 15;
275 data->right_padding = 15;
276 data->bottom_padding = 15;
277 data->left_padding = 15;
279 canvas->data = data;
282 static void
283 _adg_dispose(GObject *object)
285 AdgCanvas *canvas;
286 AdgCanvasPrivate *data;
288 canvas = (AdgCanvas *) object;
289 data = canvas->data;
291 if (data->title_block) {
292 g_object_unref(data->title_block);
293 data->title_block = NULL;
296 if (data->scales != NULL) {
297 g_strfreev(data->scales);
298 data->scales = NULL;
301 if (_ADG_OLD_OBJECT_CLASS->dispose)
302 _ADG_OLD_OBJECT_CLASS->dispose(object);
306 static void
307 _adg_get_property(GObject *object, guint prop_id,
308 GValue *value, GParamSpec *pspec)
310 AdgCanvasPrivate *data = ((AdgCanvas *) object)->data;
312 switch (prop_id) {
313 case PROP_SIZE:
314 g_value_set_boxed(value, &data->size);
315 break;
316 case PROP_SCALES:
317 g_value_set_boxed(value, data->scales);
318 break;
319 case PROP_BACKGROUND_DRESS:
320 g_value_set_enum(value, data->background_dress);
321 break;
322 case PROP_FRAME_DRESS:
323 g_value_set_enum(value, data->frame_dress);
324 break;
325 case PROP_TITLE_BLOCK:
326 g_value_set_object(value, data->title_block);
327 break;
328 case PROP_TOP_MARGIN:
329 g_value_set_double(value, data->top_margin);
330 break;
331 case PROP_RIGHT_MARGIN:
332 g_value_set_double(value, data->right_margin);
333 break;
334 case PROP_BOTTOM_MARGIN:
335 g_value_set_double(value, data->bottom_margin);
336 break;
337 case PROP_LEFT_MARGIN:
338 g_value_set_double(value, data->left_margin);
339 break;
340 case PROP_HAS_FRAME:
341 g_value_set_boolean(value, data->has_frame);
342 break;
343 case PROP_TOP_PADDING:
344 g_value_set_double(value, data->top_padding);
345 break;
346 case PROP_RIGHT_PADDING:
347 g_value_set_double(value, data->right_padding);
348 break;
349 case PROP_BOTTOM_PADDING:
350 g_value_set_double(value, data->bottom_padding);
351 break;
352 case PROP_LEFT_PADDING:
353 g_value_set_double(value, data->left_padding);
354 break;
355 default:
356 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
357 break;
361 static void
362 _adg_set_property(GObject *object, guint prop_id,
363 const GValue *value, GParamSpec *pspec)
365 AdgCanvas *canvas;
366 AdgCanvasPrivate *data;
367 AdgTitleBlock *title_block;
369 canvas = (AdgCanvas *) object;
370 data = canvas->data;
372 switch (prop_id) {
373 case PROP_SIZE:
374 cpml_pair_copy(&data->size, g_value_get_boxed(value));
375 break;
376 case PROP_SCALES:
377 g_strfreev(data->scales);
378 data->scales = g_value_dup_boxed(value);
379 break;
380 case PROP_BACKGROUND_DRESS:
381 data->background_dress = g_value_get_enum(value);
382 break;
383 case PROP_FRAME_DRESS:
384 data->frame_dress = g_value_get_enum(value);
385 break;
386 case PROP_TITLE_BLOCK:
387 title_block = g_value_get_object(value);
388 if (title_block) {
389 g_object_ref(title_block);
390 adg_entity_set_parent((AdgEntity *) title_block,
391 (AdgEntity *) canvas);
393 if (data->title_block)
394 g_object_unref(data->title_block);
395 data->title_block = title_block;
396 break;
397 case PROP_TOP_MARGIN:
398 data->top_margin = g_value_get_double(value);
399 break;
400 case PROP_RIGHT_MARGIN:
401 data->right_margin = g_value_get_double(value);
402 break;
403 case PROP_BOTTOM_MARGIN:
404 data->bottom_margin = g_value_get_double(value);
405 break;
406 case PROP_LEFT_MARGIN:
407 data->left_margin = g_value_get_double(value);
408 break;
409 case PROP_HAS_FRAME:
410 data->has_frame = g_value_get_boolean(value);
411 break;
412 case PROP_TOP_PADDING:
413 data->top_padding = g_value_get_double(value);
414 break;
415 case PROP_RIGHT_PADDING:
416 data->right_padding = g_value_get_double(value);
417 break;
418 case PROP_BOTTOM_PADDING:
419 data->bottom_padding = g_value_get_double(value);
420 break;
421 case PROP_LEFT_PADDING:
422 data->left_padding = g_value_get_double(value);
423 break;
424 default:
425 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
426 break;
432 * adg_canvas_new:
434 * Creates a new empty canvas object.
436 * Returns: (transfer full): the newly created canvas.
438 * Since: 1.0
440 AdgCanvas *
441 adg_canvas_new(void)
443 return g_object_new(ADG_TYPE_CANVAS, NULL);
447 * adg_canvas_set_size:
448 * @canvas: an #AdgCanvas
449 * @size: (transfer none): the new size for the canvas
451 * Sets a specific size on @canvas. The x and/or y
452 * component of @size can be set to 0, in which case
453 * the exact value will be autocalculated, that is the
454 * size component returned by adg_entity_get_extents()
455 * on @canvas will be used instead.
457 * Since: 1.0
459 void
460 adg_canvas_set_size(AdgCanvas *canvas, const CpmlPair *size)
462 g_return_if_fail(ADG_IS_CANVAS(canvas));
463 g_return_if_fail(size != NULL);
465 g_object_set(canvas, "size", size, NULL);
469 * adg_canvas_set_size_explicit:
470 * @canvas: an #AdgCanvas
471 * @x: the new width of the canvas or 0 to reset
472 * @y: the new height of the canvas or 0 to reset
474 * A convenient function to set the size of @canvas using
475 * explicit coordinates. Check adg_canvas_set_size() for
476 * further details.
478 * Since: 1.0
480 void
481 adg_canvas_set_size_explicit(AdgCanvas *canvas, gdouble x, gdouble y)
483 CpmlPair size;
485 size.x = x;
486 size.y = y;
488 adg_canvas_set_size(canvas, &size);
492 * adg_canvas_get_size:
493 * @canvas: an #AdgCanvas
495 * Gets the specific size set on @canvas. The x and/or y
496 * components of the returned #CpmlPair could be 0, in which
497 * case the size returned by adg_entity_get_extents() on @canvas
498 * will be used instead.
500 * Returns: (transfer none): the explicit size set on this canvas or <constant>NULL</constant> on errors.
502 * Since: 1.0
504 const CpmlPair *
505 adg_canvas_get_size(AdgCanvas *canvas)
507 AdgCanvasPrivate *data;
509 g_return_val_if_fail(ADG_IS_CANVAS(canvas), NULL);
511 data = canvas->data;
512 return &data->size;
516 * adg_canvas_set_scales:
517 * @canvas: an #AdgCanvas
518 * @...: <constant>NULL</constant> terminated list of strings
520 * Sets the scales allowed by @canvas. Every scale identifies a
521 * specific factor to be applied to the local matrix of @canvas.
522 * When adg_canvas_autoscale() will be called, the greatest
523 * scale that can render every entity inside a box of
524 * #AdgCanvas:size dimensions will be applied. The drawing will
525 * be centered inside that box.
527 * Every scale should be expressed with a string in the form of
528 * "x:y", where x and y are positive integers that identifies
529 * numerator an denominator of a fraction. That string itself
530 * will be put into the title block when used.
532 * Since: 1.0
534 void
535 adg_canvas_set_scales(AdgCanvas *canvas, ...)
537 va_list var_args;
539 va_start(var_args, canvas);
540 adg_canvas_set_scales_valist(canvas, var_args);
541 va_end(var_args);
545 * adg_canvas_set_scales_valist:
546 * @canvas: an #AdgCanvas
547 * @var_args: <constant>NULL</constant> terminated list of strings
549 * Vararg variant of adg_canvas_set_scales().
551 * Since: 1.0
553 void
554 adg_canvas_set_scales_valist(AdgCanvas *canvas, va_list var_args)
556 gchar **scales;
557 const gchar *scale;
558 gint n;
560 g_return_if_fail(ADG_IS_CANVAS(canvas));
562 scales = NULL;
563 n = 0;
564 while ((scale = va_arg(var_args, const gchar *)) != NULL) {
565 ++n;
566 scales = g_realloc(scales, sizeof(const gchar *) * (n + 1));
567 scales[n-1] = g_strdup(scale);
568 scales[n] = NULL;
571 g_object_set(canvas, "scales", scales, NULL);
572 g_strfreev(scales);
576 * adg_canvas_set_scales_array: (rename-to adg_canvas_set_scales)
577 * @canvas: an #AdgCanvas
578 * @scales: (array zero-terminated=1) (allow-none): <constant>NULL</constant> terminated array of scales
580 * Array variant of adg_canvas_set_scales().
582 * Since: 1.0
584 void
585 adg_canvas_set_scales_array(AdgCanvas *canvas, gchar **scales)
587 g_return_if_fail(ADG_IS_CANVAS(canvas));
588 g_object_set(canvas, "scales", scales, NULL);
592 * adg_canvas_get_scales:
593 * @canvas: an #AdgCanvas
595 * Gets the list of scales set on @canvas: check adg_canvas_set_scales()
596 * to get an idea of what scales are supposed to be.
598 * If no scales are set, <constant>NULL</constant> is returned.
600 * Returns: (element-type utf8) (transfer none): the <constant>NULL</constant> terminated list of valid scales.
602 * Since: 1.0
604 gchar **
605 adg_canvas_get_scales(AdgCanvas *canvas)
607 AdgCanvasPrivate *data;
609 g_return_val_if_fail(ADG_IS_CANVAS(canvas), NULL);
611 data = canvas->data;
612 return data->scales;
616 * adg_canvas_autoscale:
617 * @canvas: an #AdgCanvas
619 * Applies one scale per time, in the order they have been provided
620 * in the adg_canvas_set_scales() call, until the drawing can be
621 * entirely contained into the current paper. If successful, the
622 * scale of the title block is changed accordingly and the drawing
623 * is centered inside the paper.
625 * Since: 1.0
627 void
628 adg_canvas_autoscale(AdgCanvas *canvas)
630 AdgCanvasPrivate *data;
631 gchar **p_scale;
632 AdgEntity *entity;
633 cairo_matrix_t map;
634 const CpmlExtents *extents;
635 AdgTitleBlock *title_block;
636 CpmlPair delta;
638 g_return_if_fail(ADG_IS_CANVAS(canvas));
639 g_return_if_fail(_ADG_OLD_ENTITY_CLASS->arrange != NULL);
641 data = canvas->data;
642 entity = (AdgEntity *) canvas;
643 title_block = data->title_block;
645 /* Manually calling the arrange() method instead of emitting the "arrange"
646 * signal does not invalidate the global matrix: let's do it right now */
647 adg_entity_global_changed(entity);
649 for (p_scale = data->scales; p_scale != NULL && *p_scale != NULL; ++p_scale) {
650 const gchar *scale = *p_scale;
651 gdouble factor = adg_scale_factor(scale);
652 if (factor <= 0)
653 continue;
655 cairo_matrix_init_scale(&map, factor, factor);
656 adg_entity_set_local_map(entity, &map);
657 adg_entity_local_changed(entity);
659 /* Arrange the entities inside the canvas, but not the canvas itself,
660 * just to get the bounding box of the drawing without the paper */
661 _ADG_OLD_ENTITY_CLASS->arrange(entity);
662 extents = adg_entity_get_extents(entity);
664 /* Just in case @canvas is emtpy */
665 if (! extents->is_defined)
666 return;
668 if (title_block != NULL)
669 adg_title_block_set_scale(title_block, scale);
671 /* Bail out if paper size is not specified or invalid */
672 if (data->size.x <= 0 || data->size.y <= 0)
673 break;
675 /* If the drawing extents are fully contained inside the paper size,
676 * center the drawing in the paper and bail out */
677 delta.x = data->size.x - extents->size.x;
678 delta.y = data->size.y - extents->size.y;
679 if (delta.x >= 0 && delta.y >= 0) {
680 cairo_matrix_t transform;
681 cairo_matrix_init_translate(&transform,
682 delta.x / 2 - extents->org.x,
683 delta.y / 2 - extents->org.y);
684 adg_entity_transform_local_map(entity, &transform,
685 ADG_TRANSFORM_AFTER);
686 break;
692 * adg_canvas_set_background_dress:
693 * @canvas: an #AdgCanvas
694 * @dress: the new #AdgDress to use
696 * Sets a new background dress for rendering @canvas: the new
697 * dress must be a color dress.
699 * Since: 1.0
701 void
702 adg_canvas_set_background_dress(AdgCanvas *canvas, AdgDress dress)
704 g_return_if_fail(ADG_IS_CANVAS(canvas));
705 g_object_set(canvas, "background-dress", dress, NULL);
709 * adg_canvas_get_background_dress:
710 * @canvas: an #AdgCanvas
712 * Gets the background dress to be used in rendering @canvas.
714 * Returns: the current background dress.
716 * Since: 1.0
718 AdgDress
719 adg_canvas_get_background_dress(AdgCanvas *canvas)
721 AdgCanvasPrivate *data;
723 g_return_val_if_fail(ADG_IS_CANVAS(canvas), ADG_DRESS_UNDEFINED);
725 data = canvas->data;
727 return data->background_dress;
731 * adg_canvas_set_frame_dress:
732 * @canvas: an #AdgCanvas
733 * @dress: the new #AdgDress to use
735 * Sets the #AdgCanvas:frame-dress property of @canvas to @dress:
736 * the new dress must be a line dress.
738 * Since: 1.0
740 void
741 adg_canvas_set_frame_dress(AdgCanvas *canvas, AdgDress dress)
743 g_return_if_fail(ADG_IS_CANVAS(canvas));
744 g_object_set(canvas, "frame-dress", dress, NULL);
748 * adg_canvas_get_frame_dress:
749 * @canvas: an #AdgCanvas
751 * Gets the frame dress to be used in rendering the border of @canvas.
753 * Returns: the current frame dress.
755 * Since: 1.0
757 AdgDress
758 adg_canvas_get_frame_dress(AdgCanvas *canvas)
760 AdgCanvasPrivate *data;
762 g_return_val_if_fail(ADG_IS_CANVAS(canvas), ADG_DRESS_UNDEFINED);
764 data = canvas->data;
765 return data->frame_dress;
769 * adg_canvas_set_title_block:
770 * @canvas: an #AdgCanvas
771 * @title_block: (transfer full): a title block
773 * Sets the #AdgCanvas:title-block property of @canvas to @title_block.
775 * Although a title block entity could be added to @canvas in the usual
776 * way, that is using the adg_container_add() method, assigning a title
777 * block with adg_canvas_set_title_block() is somewhat different:
779 * - @title_block will be automatically attached to the bottom right
780 * corner of to the @canvas frame (this could be accomplished in the
781 * usual way too, by resetting the right and bottom paddings);
782 * - the @title_block boundary box is not taken into account while
783 * computing the extents of @canvas.
785 * Since: 1.0
787 void
788 adg_canvas_set_title_block(AdgCanvas *canvas,
789 AdgTitleBlock *title_block)
791 g_return_if_fail(ADG_IS_CANVAS(canvas));
792 g_return_if_fail(title_block == NULL || ADG_IS_TITLE_BLOCK(title_block));
793 g_object_set(canvas, "title-block", title_block, NULL);
797 * adg_canvas_get_title_block:
798 * @canvas: an #AdgCanvas
800 * Gets the #AdgTitleBlock object of @canvas: check
801 * adg_canvas_set_title_block() for details.
803 * The returned entity is owned by @canvas and should not be
804 * modified or freed.
806 * Returns: (transfer none): the title block object or <constant>NULL</constant>.
808 * Since: 1.0
810 AdgTitleBlock *
811 adg_canvas_get_title_block(AdgCanvas *canvas)
813 AdgCanvasPrivate *data;
815 g_return_val_if_fail(ADG_IS_CANVAS(canvas), NULL);
817 data = canvas->data;
818 return data->title_block;
822 * adg_canvas_set_top_margin:
823 * @canvas: an #AdgCanvas
824 * @value: the new margin, in global space
826 * Changes the top margin of @canvas by setting #AdgCanvas:top-margin
827 * to @value. Negative values are allowed.
829 * Since: 1.0
831 void
832 adg_canvas_set_top_margin(AdgCanvas *canvas, gdouble value)
834 g_return_if_fail(ADG_IS_CANVAS(canvas));
835 g_object_set(canvas, "top-margin", value, NULL);
839 * adg_canvas_get_top_margin:
840 * @canvas: an #AdgCanvas
842 * Gets the top margin (in global space) of @canvas.
844 * Returns: the requested margin or 0 on error.
846 * Since: 1.0
848 gdouble
849 adg_canvas_get_top_margin(AdgCanvas *canvas)
851 AdgCanvasPrivate *data;
853 g_return_val_if_fail(ADG_IS_CANVAS(canvas), 0.);
855 data = canvas->data;
856 return data->top_margin;
860 * adg_canvas_set_right_margin:
861 * @canvas: an #AdgCanvas
862 * @value: the new margin, in global space
864 * Changes the right margin of @canvas by setting
865 * #AdgCanvas:right-margin to @value. Negative values are allowed.
867 * Since: 1.0
869 void
870 adg_canvas_set_right_margin(AdgCanvas *canvas, gdouble value)
872 g_return_if_fail(ADG_IS_CANVAS(canvas));
873 g_object_set(canvas, "right-margin", value, NULL);
877 * adg_canvas_get_right_margin:
878 * @canvas: an #AdgCanvas
880 * Gets the right margin (in global space) of @canvas.
882 * Returns: the requested margin or 0 on error.
884 * Since: 1.0
886 gdouble
887 adg_canvas_get_right_margin(AdgCanvas *canvas)
889 AdgCanvasPrivate *data;
891 g_return_val_if_fail(ADG_IS_CANVAS(canvas), 0.);
893 data = canvas->data;
894 return data->right_margin;
898 * adg_canvas_set_bottom_margin:
899 * @canvas: an #AdgCanvas
900 * @value: the new margin, in global space
902 * Changes the bottom margin of @canvas by setting
903 * #AdgCanvas:bottom-margin to @value. Negative values are allowed.
905 * Since: 1.0
907 void
908 adg_canvas_set_bottom_margin(AdgCanvas *canvas, gdouble value)
910 g_return_if_fail(ADG_IS_CANVAS(canvas));
911 g_object_set(canvas, "bottom-margin", value, NULL);
915 * adg_canvas_get_bottom_margin:
916 * @canvas: an #AdgCanvas
918 * Gets the bottom margin (in global space) of @canvas.
920 * Returns: the requested margin or 0 on error.
922 * Since: 1.0
924 gdouble
925 adg_canvas_get_bottom_margin(AdgCanvas *canvas)
927 AdgCanvasPrivate *data;
929 g_return_val_if_fail(ADG_IS_CANVAS(canvas), 0.);
931 data = canvas->data;
932 return data->bottom_margin;
936 * adg_canvas_set_left_margin:
937 * @canvas: an #AdgCanvas
938 * @value: the new margin, in global space
940 * Changes the left margin of @canvas by setting
941 * #AdgCanvas:left-margin to @value. Negative values are allowed.
943 * Since: 1.0
945 void
946 adg_canvas_set_left_margin(AdgCanvas *canvas, gdouble value)
948 g_return_if_fail(ADG_IS_CANVAS(canvas));
949 g_object_set(canvas, "left-margin", value, NULL);
953 * adg_canvas_get_left_margin:
954 * @canvas: an #AdgCanvas
956 * Gets the left margin (in global space) of @canvas.
958 * Returns: the requested margin or 0 on error.
960 * Since: 1.0
962 gdouble
963 adg_canvas_get_left_margin(AdgCanvas *canvas)
965 AdgCanvasPrivate *data;
967 g_return_val_if_fail(ADG_IS_CANVAS(canvas), 0.);
969 data = canvas->data;
970 return data->left_margin;
974 * adg_canvas_set_margins:
975 * @canvas: an #AdgCanvas
976 * @top: top margin, in global space
977 * @right: right margin, in global space
978 * @bottom: bottom margin, in global space
979 * @left: left margin, in global space
981 * Convenient function to set all the margins at once.
983 * Since: 1.0
985 void
986 adg_canvas_set_margins(AdgCanvas *canvas,
987 gdouble top, gdouble right,
988 gdouble bottom, gdouble left)
990 g_return_if_fail(ADG_IS_CANVAS(canvas));
991 g_object_set(canvas, "top-margin", top, "right-margin", right,
992 "bottom-margin", bottom, "left-margin", left, NULL);
996 * adg_canvas_apply_margins:
997 * @canvas: an #AdgCanvas
998 * @extents: where apply the margins
1000 * A convenient function to apply the margins of @canvas to the
1001 * arbitrary #CpmlExtents struct @extents.
1003 * Since: 1.0
1005 void
1006 adg_canvas_apply_margins(AdgCanvas *canvas, CpmlExtents *extents)
1008 AdgCanvasPrivate *data;
1010 g_return_if_fail(ADG_IS_CANVAS(canvas));
1012 data = canvas->data;
1014 extents->org.x -= data->left_margin;
1015 extents->org.y -= data->top_margin;
1016 extents->size.x += data->left_margin + data->right_margin;
1017 extents->size.y += data->top_margin + data->bottom_margin;
1021 * adg_canvas_switch_frame:
1022 * @canvas: an #AdgCanvas
1023 * @new_state: the new flag status
1025 * Sets a new status on the #AdgCanvas:has-frame
1026 * property: <constant>TRUE</constant> means a border around
1027 * the canvas extents (less the margins) should be rendered.
1029 * Since: 1.0
1031 void
1032 adg_canvas_switch_frame(AdgCanvas *canvas, gboolean new_state)
1034 g_return_if_fail(ADG_IS_CANVAS(canvas));
1035 g_object_set(canvas, "has-frame", new_state, NULL);
1039 * adg_canvas_has_frame:
1040 * @canvas: an #AdgCanvas
1042 * Gets the current status of the #AdgCanvas:has-frame property,
1043 * that is whether a border around the canvas extents (less the
1044 * margins) should be rendered (<constant>TRUE</constant>) or not
1045 * (<constant>FALSE</constant>).
1047 * Returns: the current status of the frame flag.
1049 * Since: 1.0
1051 gboolean
1052 adg_canvas_has_frame(AdgCanvas *canvas)
1054 AdgCanvasPrivate *data;
1056 g_return_val_if_fail(ADG_IS_CANVAS(canvas), FALSE);
1058 data = canvas->data;
1059 return data->has_frame;
1063 * adg_canvas_set_top_padding:
1064 * @canvas: an #AdgCanvas
1065 * @value: the new padding, in global space
1067 * Changes the top padding of @canvas by setting
1068 * #AdgCanvas:top-padding to @value. Negative values are allowed.
1070 * Since: 1.0
1072 void
1073 adg_canvas_set_top_padding(AdgCanvas *canvas, gdouble value)
1075 g_return_if_fail(ADG_IS_CANVAS(canvas));
1076 g_object_set(canvas, "top-padding", value, NULL);
1080 * adg_canvas_get_top_padding:
1081 * @canvas: an #AdgCanvas
1083 * Gets the top padding (in global space) of @canvas.
1085 * Returns: the requested padding or 0 on error.
1087 * Since: 1.0
1089 gdouble
1090 adg_canvas_get_top_padding(AdgCanvas *canvas)
1092 AdgCanvasPrivate *data;
1094 g_return_val_if_fail(ADG_IS_CANVAS(canvas), 0.);
1096 data = canvas->data;
1097 return data->top_padding;
1101 * adg_canvas_set_right_padding:
1102 * @canvas: an #AdgCanvas
1103 * @value: the new padding, in global space
1105 * Changes the right padding of @canvas by setting #AdgCanvas:right-padding
1106 * to @value. Negative values are allowed.
1108 * Since: 1.0
1110 void
1111 adg_canvas_set_right_padding(AdgCanvas *canvas, gdouble value)
1113 g_return_if_fail(ADG_IS_CANVAS(canvas));
1114 g_object_set(canvas, "right-padding", value, NULL);
1118 * adg_canvas_get_right_padding:
1119 * @canvas: an #AdgCanvas
1121 * Gets the right padding (in global space) of @canvas.
1123 * Returns: the requested padding or 0 on error.
1125 * Since: 1.0
1127 gdouble
1128 adg_canvas_get_right_padding(AdgCanvas *canvas)
1130 AdgCanvasPrivate *data;
1132 g_return_val_if_fail(ADG_IS_CANVAS(canvas), 0.);
1134 data = canvas->data;
1135 return data->right_padding;
1140 * adg_canvas_set_bottom_padding:
1141 * @canvas: an #AdgCanvas
1142 * @value: the new padding, in global space
1144 * Changes the bottom padding of @canvas by setting
1145 * #AdgCanvas:bottom-padding to @value. Negative values are allowed.
1147 * Since: 1.0
1149 void
1150 adg_canvas_set_bottom_padding(AdgCanvas *canvas, gdouble value)
1152 g_return_if_fail(ADG_IS_CANVAS(canvas));
1153 g_object_set(canvas, "bottom-padding", value, NULL);
1157 * adg_canvas_get_bottom_padding:
1158 * @canvas: an #AdgCanvas
1160 * Gets the bottom padding (in global space) of @canvas.
1162 * Returns: the requested padding or 0 on error.
1164 * Since: 1.0
1166 gdouble
1167 adg_canvas_get_bottom_padding(AdgCanvas *canvas)
1169 AdgCanvasPrivate *data;
1171 g_return_val_if_fail(ADG_IS_CANVAS(canvas), 0.);
1173 data = canvas->data;
1174 return data->bottom_padding;
1178 * adg_canvas_set_left_padding:
1179 * @canvas: an #AdgCanvas
1180 * @value: the new padding, in global space
1182 * Changes the left padding of @canvas by setting
1183 * #AdgCanvas:left-padding to @value. Negative values are allowed.
1185 * Since: 1.0
1187 void
1188 adg_canvas_set_left_padding(AdgCanvas *canvas, gdouble value)
1190 g_return_if_fail(ADG_IS_CANVAS(canvas));
1191 g_object_set(canvas, "left-padding", value, NULL);
1195 * adg_canvas_get_left_padding:
1196 * @canvas: an #AdgCanvas
1198 * Gets the left padding (in global space) of @canvas.
1200 * Returns: the requested padding or 0 on error.
1202 * Since: 1.0
1204 gdouble
1205 adg_canvas_get_left_padding(AdgCanvas *canvas)
1207 AdgCanvasPrivate *data;
1209 g_return_val_if_fail(ADG_IS_CANVAS(canvas), 0.);
1211 data = canvas->data;
1212 return data->left_padding;
1216 * adg_canvas_set_paddings:
1217 * @canvas: an #AdgCanvas
1218 * @top: top padding, in global space
1219 * @right: right padding, in global space
1220 * @bottom: bottom padding, in global space
1221 * @left: left padding, in global space
1223 * Convenient function to set all the paddings at once.
1225 * Since: 1.0
1227 void
1228 adg_canvas_set_paddings(AdgCanvas *canvas,
1229 gdouble top, gdouble right,
1230 gdouble bottom, gdouble left)
1232 g_return_if_fail(ADG_IS_CANVAS(canvas));
1233 g_object_set(canvas, "top-padding", top, "right-padding", right,
1234 "bottom-padding", bottom, "left-padding", left, NULL);
1238 static void
1239 _adg_global_changed(AdgEntity *entity)
1241 AdgCanvasPrivate *data = ((AdgCanvas *) entity)->data;
1243 if (_ADG_OLD_ENTITY_CLASS->global_changed)
1244 _ADG_OLD_ENTITY_CLASS->global_changed(entity);
1246 if (data->title_block)
1247 adg_entity_global_changed((AdgEntity *) data->title_block);
1250 static void
1251 _adg_local_changed(AdgEntity *entity)
1253 AdgCanvasPrivate *data = ((AdgCanvas *) entity)->data;
1254 AdgTitleBlock *title_block = data->title_block;
1256 if (_ADG_OLD_ENTITY_CLASS->local_changed)
1257 _ADG_OLD_ENTITY_CLASS->local_changed(entity);
1259 if (title_block != NULL) {
1260 const gchar *scale = adg_title_block_get_scale(title_block);
1262 if (scale != NULL && scale[0] != '\0') {
1263 const cairo_matrix_t *map = adg_entity_get_local_map(entity);
1264 gdouble factor = adg_scale_factor(scale);
1266 if (map->xx != factor || map->yy != factor)
1267 adg_title_block_set_scale(title_block, "---");
1270 adg_entity_local_changed((AdgEntity *) title_block);
1274 static void
1275 _adg_invalidate(AdgEntity *entity)
1277 AdgCanvasPrivate *data = ((AdgCanvas *) entity)->data;
1279 if (_ADG_OLD_ENTITY_CLASS->invalidate)
1280 _ADG_OLD_ENTITY_CLASS->invalidate(entity);
1282 if (data->title_block)
1283 adg_entity_invalidate((AdgEntity *) data->title_block);
1286 static void
1287 _adg_arrange(AdgEntity *entity)
1289 AdgCanvasPrivate *data;
1290 CpmlExtents extents;
1292 if (_ADG_OLD_ENTITY_CLASS->arrange)
1293 _ADG_OLD_ENTITY_CLASS->arrange(entity);
1295 cpml_extents_copy(&extents, adg_entity_get_extents(entity));
1297 /* The extents should be defined, otherwise there is no drawing */
1298 g_return_if_fail(extents.is_defined);
1300 data = ((AdgCanvas *) entity)->data;
1302 if (data->size.x > 0 || data->size.y > 0) {
1303 const cairo_matrix_t *global = adg_entity_get_global_matrix(entity);
1304 CpmlExtents paper;
1306 paper.org.x = 0;
1307 paper.org.y = 0;
1308 paper.size.x = data->size.x;
1309 paper.size.y = data->size.y;
1311 cairo_matrix_transform_point(global, &paper.org.x, &paper.org.y);
1312 cairo_matrix_transform_distance(global, &paper.size.x, &paper.size.y);
1314 if (data->size.x > 0) {
1315 extents.org.x = paper.org.x;
1316 extents.size.x = paper.size.x;
1318 if (data->size.y > 0) {
1319 extents.org.y = paper.org.y;
1320 extents.size.y = paper.size.y;
1324 if (data->size.x == 0) {
1325 extents.org.x -= data->left_padding;
1326 extents.size.x += data->left_padding + data->right_padding;
1328 if (data->size.y == 0) {
1329 extents.org.y -= data->top_padding;
1330 extents.size.y += data->top_padding + data->bottom_padding;
1333 /* Impose the new extents */
1334 adg_entity_set_extents(entity, &extents);
1336 if (data->title_block) {
1337 AdgEntity *title_block_entity;
1338 const CpmlExtents *title_block_extents;
1339 CpmlPair shift;
1341 title_block_entity = (AdgEntity *) data->title_block;
1342 adg_entity_arrange(title_block_entity);
1343 title_block_extents = adg_entity_get_extents(title_block_entity);
1345 shift.x = extents.org.x + extents.size.x - title_block_extents->org.x
1346 - title_block_extents->size.x;
1347 shift.y = extents.org.y + extents.size.y - title_block_extents->org.y
1348 - title_block_extents->size.y;
1350 /* The following block could be optimized by skipping tiny shift,
1351 * usually left by rounding errors */
1352 if (shift.x != 0 || shift.y != 0) {
1353 cairo_matrix_t unglobal, map;
1354 adg_matrix_copy(&unglobal, adg_entity_get_global_matrix(entity));
1355 cairo_matrix_invert(&unglobal);
1357 cairo_matrix_transform_distance(&unglobal, &shift.x, &shift.y);
1358 cairo_matrix_init_translate(&map, shift.x, shift.y);
1359 adg_entity_transform_global_map(title_block_entity, &map,
1360 ADG_TRANSFORM_AFTER);
1362 adg_entity_global_changed(title_block_entity);
1363 adg_entity_arrange(title_block_entity);
1368 static void
1369 _adg_render(AdgEntity *entity, cairo_t *cr)
1371 AdgCanvasPrivate *data;
1372 const CpmlExtents *extents;
1374 data = ((AdgCanvas *) entity)->data;
1375 extents = adg_entity_get_extents(entity);
1377 cairo_save(cr);
1379 /* Background fill */
1380 cairo_rectangle(cr, extents->org.x - data->left_margin,
1381 extents->org.y - data->top_margin,
1382 extents->size.x + data->left_margin + data->right_margin,
1383 extents->size.y + data->top_margin + data->bottom_margin);
1384 adg_entity_apply_dress(entity, data->background_dress, cr);
1385 cairo_fill(cr);
1387 /* Frame line */
1388 if (data->has_frame) {
1389 cairo_rectangle(cr, extents->org.x, extents->org.y,
1390 extents->size.x, extents->size.y);
1391 cairo_transform(cr, adg_entity_get_global_matrix(entity));
1392 adg_entity_apply_dress(entity, data->frame_dress, cr);
1393 cairo_stroke(cr);
1396 cairo_restore(cr);
1398 if (data->title_block)
1399 adg_entity_render((AdgEntity *) data->title_block, cr);
1401 if (_ADG_OLD_ENTITY_CLASS->render)
1402 _ADG_OLD_ENTITY_CLASS->render(entity, cr);
1406 #if GTK3_ENABLED || GTK2_ENABLED
1409 * adg_canvas_set_paper:
1410 * @canvas: an #AdgCanvas
1411 * @paper_name: a paper name
1412 * @orientation: the page orientation
1414 * A convenient function to set the size of @canvas using a
1415 * @paper_name and an @orientation value. This should be a
1416 * PWG 5101.1-2002 paper name and it will be passed as is to
1417 * gtk_paper_size_new(), so use any valid name accepted by
1418 * that function.
1420 * To reset this size, you could use adg_canvas_set_size()
1421 * with a <constant>NULL</constant> size: in this way the
1422 * size will match the boundary boxes of the entities
1423 * contained by the canvas.
1425 * Furthermore, the margins will be set to their default values,
1426 * that is the margins returned by the #GtkPaperSize API.
1427 * If you want to use your own margins on a named paper size,
1428 * set them <emphasis>after</emphasis> the call to this function.
1430 * Since: 1.0
1432 void
1433 adg_canvas_set_paper(AdgCanvas *canvas,
1434 const gchar *paper_name,
1435 GtkPageOrientation orientation)
1437 GtkPageSetup *page_setup;
1438 GtkPaperSize *paper_size;
1440 g_return_if_fail(ADG_IS_CANVAS(canvas));
1441 g_return_if_fail(paper_name != NULL);
1443 page_setup = gtk_page_setup_new();
1444 paper_size = gtk_paper_size_new(paper_name);
1446 gtk_page_setup_set_paper_size(page_setup, paper_size);
1447 gtk_page_setup_set_orientation(page_setup, orientation);
1448 gtk_paper_size_free(paper_size);
1450 adg_canvas_set_page_setup(canvas, page_setup);
1451 g_object_unref(page_setup);
1455 * adg_canvas_set_page_setup:
1456 * @canvas: an #AdgCanvas
1457 * @page_setup: (allow-none) (transfer none): the page setup
1459 * A convenient function to setup the page of @canvas so it can
1460 * also be subsequentially used for printing. It is allowed to
1461 * pass <constant>NULL</constant> for @page_setup to unset the
1462 * setup data from @canvas.
1464 * A reference to @page_setup is added, so there is no need to keep
1465 * alive this object outside this function. The @page_setup pointer
1466 * is stored in the associative key <constant>"_adg_page_setup"</constant>
1467 * and can be retrieved at any time with adg_canvas_get_page_setup().
1469 * The size and margins provided by @page_setup are used to set the
1470 * size and margins of @canvas much in the same way as what
1471 * adg_canvas_set_paper() does. This means if you set a page and
1472 * then unset it, the canvas will retain size and margins of the
1473 * original page although @page_setup will not be used for printing.
1474 * You must unset the size with adg_canvas_set_size()
1475 * with a <constant>NULL</constant> size.
1477 * <informalexample><programlisting language="C">
1478 * // By default, canvas does not have an explicit size
1479 * adg_canvas_set_page_setup(canvas, a4);
1480 * // Here canvas has the size and margins specified by a4
1481 * adg_canvas_set_page_setup(canvas, NULL);
1482 * // Now the only difference is that canvas is no more bound
1483 * // to the a4 page setup, so the following will return NULL:
1484 * page_setup = adg_canvas_get_page_setup(canvas);
1485 * // To restore the original status and have an autocomputed size:
1486 * adg_canvas_set_size(canvas, NULL);
1487 * </programlisting></informalexample>
1489 * Since: 1.0
1491 void
1492 adg_canvas_set_page_setup(AdgCanvas *canvas, GtkPageSetup *page_setup)
1494 gdouble top, right, bottom, left;
1495 CpmlPair size;
1497 g_return_if_fail(ADG_IS_CANVAS(canvas));
1499 if (page_setup == NULL) {
1500 /* By convention, NULL resets the default page but
1501 * does not change any other property */
1502 g_object_set_data((GObject *) canvas, "_adg_page_setup", NULL);
1503 return;
1506 g_return_if_fail(GTK_IS_PAGE_SETUP(page_setup));
1508 top = gtk_page_setup_get_top_margin(page_setup, GTK_UNIT_POINTS);
1509 right = gtk_page_setup_get_right_margin(page_setup, GTK_UNIT_POINTS);
1510 bottom = gtk_page_setup_get_bottom_margin(page_setup, GTK_UNIT_POINTS);
1511 left = gtk_page_setup_get_left_margin(page_setup, GTK_UNIT_POINTS);
1512 size.x = gtk_page_setup_get_page_width(page_setup, GTK_UNIT_POINTS);
1513 size.y = gtk_page_setup_get_page_height(page_setup, GTK_UNIT_POINTS);
1515 adg_canvas_set_size(canvas, &size);
1516 adg_canvas_set_margins(canvas, top, right, bottom, left);
1518 g_object_ref(page_setup);
1519 g_object_set_data_full((GObject *) canvas, "_adg_page_setup",
1520 page_setup, g_object_unref);
1524 * adg_canvas_get_page_setup:
1525 * @canvas: an #AdgCanvas
1527 * If adg_canvas_set_page_setup() is called, a #GtkPageSetup object
1528 * is created and bound to @canvas. This metho returns a pointer
1529 * to that internal object or <constant>NULL</constant> if
1530 * adg_canvas_set_page_setup() has not been called before.
1532 * Returns: (allow-none) (transfer none): the #GtkPageSetup with size and margins of @canvas of <constant>NULL</constant> on no setup found or errors.
1534 * Since: 1.0
1536 GtkPageSetup *
1537 adg_canvas_get_page_setup(AdgCanvas *canvas)
1539 g_return_val_if_fail(ADG_IS_CANVAS(canvas), NULL);
1540 return g_object_get_data((GObject *) canvas, "_adg_page_setup");
1543 #endif